状态模式

# 分类

行为型模式

# 定义

状态模式(State Pattern) 在状态模式中,类的行为是基于它的状态改变的。

# 意图

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

# 应用场景

  • 行为随状态改变而改变的场景。
  • 条件、分支语句的代替者。
  • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式了。

应用案例

打篮球的时候运动员可以有正常状态、不正常状态和超常状态。

# 角色与结构图

  • State:抽象状态类角色 定义一个接口以封装与Context的一个特定状态相关的行为。
  • ConcreteState:具体状态类角色 每一个子类实现一个与Context的一个状态相关的行为。
  • Context:上下文类角色 维护一个ConcreteState子类的实例,这个实例定义当前的状态。
  • Client:客户端程序角色 调用接口,实现功能。

下图解释了状态模式中各角色的作用

<<------------------------状态模式结构图--------------------------->>

# 示例代码

// 状态抽象类
abstract class State {
  public abstract void Handle(Context context);
}
// 具体状态A
class ConcreteStateA : State {
  public override void Handle(Context context){
    context.State = new ConcreteStateB();
  }
}
// 具体状态B
class ConcreteStateB : State {
  public override void Handle(Context context){
    context.State = new ConcreteStateA();
  }
}

// 上下文
class Context{
  private State state;

  public Context(State state){
    this.state = state;
  }
  public State State{
    get{return this.state;}
    set{
      state = value;
      Console.WriteLine("当前状态:" + state.GetType().Name);
    }
  }
  public void Request(){
    state.Handle(this);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 客户端
class Client{
  static void Main(String[] args){
    Context context = new Context(new ConcreteStateA());
    context.request();
    context.request();
    context.request();
    context.request();
    context.request();

    Console.ReadLine();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 优点

  • 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
  • 将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个具体状态类中,所以通过定义新的子类可以很容易地增加新的状态和转换。
  • 可以消除庞大的条件分支语句,大的分支判断会使它们难以修改和扩展,任何一个地方的改动和变化都是致命的。状态模式通过把各种状态逻辑转移分布到State的子类之间,来减少相互间的依赖。
  • 封装了转换规则。
  • 枚举可能的状态,在枚举状态之前需要确定状态种类。
  • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

# 缺点

  • 状态模式的使用必然会增加系统类和对象的个数。
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱。
  • 状态模式对开闭原则的支持并不太好,对于切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新状态,而且修改某个状态类和行为也需要修改对应类的源代码。

# 小结

  • 主要解决?对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用状态模式了。
  • 何时使用?代码中包含大量与对象状态有关的条件语句。
  • 如何解决?将各种具体的状态类抽象出来。
  • 关键代码?通常命令模式的接口中只有一个方法,而状态模式中的接口中可有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样用于消除if...else...等条件选择语句。
  • 注意:在行为受状态约束的时候使用状态模式,而且状态不超过5个。

# 一句话概括

状态类里封装了对应的行为,切换状态即切换行为。

上次更新: 2025/03/22, 13:47:44
最近更新
01
Git问题集合
01-29
02
安装 Nginx 服务器
01-25
03
安装 Docker 容器
01-25
更多文章>
×
×