ios 状态模式

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

在很多情况下, 一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做 状态,这样的对象叫做 有状态的 ( stateful ) 对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。

适用性

在下面的两种情况下均可使用State模式:
1) •  一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
2) •  代码中包含大量与对象状态有关的条件语句 :一个操作中含有庞大的多分支的条件(if else(或switch case)语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

结构

模式的组成

环境类(Context):  定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
抽象状态类(State):  定义一个接口以封装与Context的一个特定状态相关的行为。
具体状态类(ConcreteState):  每一子类实现一个与Context的一个状态相关的行为。

效果

State模式有下面一些效果:
状态模式的优点:
1 ) 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来: State模式将所有与一个特定的状态相关的行为都放入一个对象中。因为所有与状态相关的代码都存在于某一个State子类中, 所以通过定义新的子类可以很容易的增加新的状态和转换。另一个方法是使用数据值定义内部状态并且让 Context操作来显式地检查这些数据。但这样将会使整个Context的实现中遍布看起来很相似的条件if else语句或switch case语句。增加一个新的状态可能需要改变若干个操作, 这就使得维护变得复杂了。State模式避免了这个问题, 但可能会引入另一个问题, 因为该模式将不同状态的行为分布在多个State子类中。这就增加了子类的数目,相对于单个类的实现来说不够紧凑。但是如果有许多状态时这样的分布实际上更好一些, 否则需要使用巨大的条件语句。正如很长的过程一样,巨大的条件语句是不受欢迎的。它们形成一大整块并且使得代码不够清晰,这又使得它们难以修改和扩展。 State模式提供了一个更好的方法来组织与特定状态相关的代码。决定状态转移的逻辑不在单块的 i f或s w i t c h语句中, 而是分布在State子类之间。将每一个状态转换和动作封装到一个类中,就把着眼点从执行状态提高到整个对象的状态。这将使代码结构化并使其意图更加清晰。

2) 它使得状态转换显式化: 当一个对象仅以内部数据值来定义当前状态时 , 其状态仅表现为对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得转换变得更加明确。而且, State对象可保证Context不会发生内部状态不一致的情况,因为从 Context的角度看,状态转换是原子的—只需重新绑定一个变量(即Context的State对象变量),而无需为多个变量赋值

3) State对象可被共享 如果State对象没有实例变量—即它们表示的状态完全以它们的类型来编码—那么各Context对象可以共享一个State对象。当状态以这种方式被共享时, 它们必然是没有内部状态, 只有行为的轻量级对象。

状态模式的缺点:
1) 状态模式的使用必然会增加系统类和对象的个数。
2) 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

  4.2 状态模式的代码实现

/// <summary>
/// Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态。
/// </summary>
public class Context
{
    private State state;
    /// <summary>
    /// 定义Context的初始状态
    /// </summary>
    /// <param name="state"></param>
    public Context(State state)
    {
        this.state = state;
    }

    /// <summary>
    /// 可读写的状态属性,用于读取和设置新状态
    /// </summary>
    public State State
    {
        get { return state; }
        set { state = value; }
    }

    /// <summary>
    /// 对请求做处理,并设置下一个状态
    /// </summary>
    public void Request()
    {
        state.Handle(this);
    }
}

/// <summary>
/// 抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
/// </summary>
public abstract class State
{
    public abstract void Handle(Context context);
}

/// <summary>
/// 具体状态类,每一个子类实现一个与Context的一个状态相关的行为
/// </summary>
public class ConcreteStateA : State
{
    /// <summary>
    /// 设置ConcreteStateA的下一个状态是ConcreteStateB
    /// </summary>
    /// <param name="context"></param>
    public override void Handle(Context context)
    {
        Console.WriteLine("当前状态是 A.");
        context.State = new ConcreteStateB();
    }
}

public class ConcreteStateB : State
{
    /// <summary>
    /// 设置ConcreteStateB的下一个状态是ConcreteSateA
    /// </summary>
    /// <param name="context"></param>
    public override void Handle(Context context)
    {
        Console.WriteLine("当前状态是 B.");
        context.State = new ConcreteStateA();
    }
}

4.3 客户端调用

class Program
{
    static void Main(string[] args)
    {
        // 设置Context的初始状态为ConcreteStateA
        Context context = new Context(new ConcreteStateA());

        // 不断地进行请求,同时更改状态
        context.Request();
        context.Request();
        context.Request();
        context.Request();

        Console.Read();
    }
}

运行结果

5. 模式总结

5.1 优点

  5.1.1 状态模式将与特定状态相关的行为对象化,并且将不同状态的行为分割开来。

  5.1.2 所有状态相关的代码都存在于某个ConcereteState中,所以通过定义新的子类很容易地增加新的状态和转换。

  5.1.3 状态模式通过把各种状态转移逻辑分不到State的子类之间,来减少相互间的依赖。

5.2 缺点

  5.2.1 导致较多的ConcreteState子类

5.3 适用场景

  5.3.1 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式来。

  5.3.2 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态。

6. 应用举例:电灯有两个状态,开(亮)与关(不亮),下面就用状态模式来实现对电灯的控制。

  6.1 类图

  

6.2 实现代码

/// <summary>
/// 电灯类,对应模式中的Context类
/// </summary>
public class Light
{
    private LightState state;

    public Light(LightState state)
    {
        this.state = state;
    }

    /// <summary>
    /// 按下电灯开关
    /// </summary>
    public void PressSwich()
    {
        state.PressSwich(this);
    }

    public LightState State
    {
        get { return state; }
        set { state = value; }
    }    
}

/// <summary>
/// 抽象的电灯状态类,相当于State类
/// </summary>
public abstract class LightState
{
    public abstract void PressSwich(Light light);
}

/// <summary>
/// 具体状态类, 开
/// </summary>
public class On : LightState
{
    /// <summary>
    /// 在开状态下,按下开关则切换到关的状态。
    /// </summary>
    /// <param name="light"></param>
    public override void PressSwich(Light light)
    {
        Console.WriteLine("Turn off the light.");

        light.State = new Off();
    }
}

/// <summary>
/// 具体状态类,关
/// </summary>
public class Off: LightState
{
    /// <summary>
    /// 在关状态下,按下开关则打开电灯。
    /// </summary>
    /// <param name="light"></param>
    public override void PressSwich(Light light)
    {
        Console.WriteLine("Turn on the light.");

        light.State = new On();
    }
}

6.3 客户端代码

class Program
{
    static void Main(string[] args)
    {
        // 初始化电灯,原始状态为关
        Light light = new Light(new Off());

        // 第一次按下开关,打开电灯
        light.PressSwich();
        // 第二次按下开关,关闭电灯
        light.PressSwich();

        Console.Read();
    }
}

执行结果

其他参考文章: 状态模式——每天学习一种设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值