设计模式(二十一)—— 状态模式

模式简介


允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

在某些情况下,一个对象的行为取决于它当前所处的状态,当对象属性(状态)在系统运行过程中发生变化,它呈现出的行为也随之发生改变。例如可调节亮度的台灯,假设灯光亮度分为三级,每次按下按钮,台灯会根据当前亮度增加一级,若已经是最亮的状态,按下按钮则关闭台灯。

结构分析


UML类图

角色说明

  • Context

环境类。客户端操作的类,包含一个IState类型的对象,保存其当前状态。

  • IState

状态接口。定义一个统一的接口以封装与Context的特定状态相关的行为。

  • ConcreteState

具体状态。实现状态接口,表示Context某个状态相关的行为。

工作原理

Context类将与状态相关的请求委托给ConcreteState对象处理,并将自身以参数形式传递给ConcreteState对象,如此,便可以在处理完请求后访问Context的SetState方法为Context设置新的状态。

结构代码

//环境类
class Context
{
    private IState _state;
    public Context(IState state)
    {
        _state = state;
        Console.WriteLine($"Initialize state -> {state}");
    }

    public void SetState(IState state)
    {
        _state = state;
        Console.WriteLine($"Set State -> {state}");
    }

    public void Request()
    {
        _state.Handle(this);
    }
}

//状态接口
interface IState
{
    void Handle(Context context);
}

//具体状态类A
class ConcreteStateA : IState
{
    public void Handle(Context context)
    {
        context.SetState(new ConcreteStateB());
    }
}

//具体状态类B
class ConcreteStateB : IState
{
    public void Handle(Context context)
    {
        context.SetState(new ConcreteStateA());
    }
}

//客户端调用
static void Main(string[] args)
{
    Context context = new Context(new ConcreteStateA());
    for (int i = 0; i < 5; i++)
    {
        context.Request();
    }
    Console.ReadLine();
}

程序输出:

示例分析


本节模拟第一节中提到的台灯示例。首先创建台灯类Lamp,提供共有方法SetState设置当前状态,包含一个保存当前状态的私有字段_state,并通过Request方法调用该状态的下台灯发光的行为。

class Lamp
{
    private IState _state;
    public Lamp(IState state)
    {
        _state = state;
        Console.WriteLine($"Initialize state -> {state}");
    }
    public void SetState(IState state)
    {
        _state = state;
        Console.WriteLine($"Set State -> {state}");
    }

    public void Request()
    {
        _state.Handle(this);
    }
}

声明状态接口,并分别实现具体状态类,这里包括四种状态Closed、Dim、Medium、Bright。

interface IState
{
    void Handle(Lamp context);
}

class Closed : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Dim());
    }
}

class Dim : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Medium());
    }
}

class Medium : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Bright());
    }
}

class Bright : IState
{
    public void Handle(Lamp context)
    {
        context.SetState(new Closed());
    }
}

客户端调用,将台灯的初始状态设置为Closed,并连续调用,输出台灯状态。

class Program
{
    static void Main(string[] args)
    {
        Lamp lamp = new Lamp(new Closed());
        for (int i = 0; i < 10; i++)
        {
            lamp.Request();
        }
        Console.ReadLine();
    }
}

程序输出:

适用场景


  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

  • 一个操作中含有大量的分支的条件语句,且这些分支依赖于该对象的状态。

posted @ 2018-07-16 20:05 Answer.Geng 阅读(...) 评论(...) 编辑 收藏