状态模式(State Pattern)

一、概念

状态模式(State Pattern)也称为状态机模式(State Machine Pattern),当控制一个对象状态的条件表达式过于复杂的时候,就可以考虑使用状态模式,通过把状态的判断逻辑转移到表示不同状态的一系列类中,这样就可以把复杂的逻辑简单化,使得对象的行为依赖于它的状态,并且会随着状态的改变而同时改变行为。

  • 所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,再具体点说,行为大多可以 对应到方法上

  • 状态模式的核心就是 分离对象的状态和行为,通过维护状态的变化,来调用不同状态对应的不同功能。 也就是说,状态和行为是相关联的,即: 状态决定行为(功能)

  • 由于状态是在运行期被改变的,因此行为也会在运行期根据状态的改变而改变

  • 和 策略模式 一样可以减少if-else或switch-case等条件判断逻辑。

二、适用场景

状态模式主要应用于以下场景:

  1. 对象的行为(功能)需要随着状态的改变而改变时。
  2. 当我们一个操作中需要根据状态来写大量的if/else逻辑时

三、参与者

  • 环境类角色/状态处理角色(Context):定义客户类需要的接口,内部一个具体状态的实例,并负责具体状态的切换
    • 在状态模式中,环境(Context)是持有状态的对象,但是环境(Context)自身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理。
  • 抽象状态角色(Abstract State):接口或者抽象类。定义每个状态下对应的行为(功能方法),可以有一个或者多个行为(功能方法)
  • 具体状态角色/上下文角色(Concrete State):具体实现该状态对应的行为(功能方法),并且在需要的情况下实现状态的切换。
    • 具体的状态处理类中经常需要获取环境(Context)自身的数据,甚至在必要的时候会回调环境(Context)的方法,因此,通常将环境(Context)自身当作一个参数传递给具体的状态处理类
  • 客户类(Client):使用环境类角色完成状态装换
    • 客户端一般只和环境(Context)交互。客户端可以用状态对象来配置一个环境(Context),一旦配置完毕,就不再需要和状态对象打交道了。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象。

四、代码例子

绘图板它有三种画笔颜色,分别是红色、黄色、蓝色,我们可以设置当前画笔的颜色之后再绘图板上绘制指定图形

环境类角色/状态处理角色(Context):WhiteBoard

抽象状态角色(Abstract State):DrawState

具体状态角色/上下文角色(Concrete State):DrawRed、DrawYellow、DrawBlue

五、UML图

六、优缺点

(一)优点

  1. 通过将每个状态设置为独立的对象消除了代码中存在的大量if/else等判断分支,使得代码更加简洁,更容易维护。
  2. 将不同的状态通过不同的类来表示,使得状态切换时比用数字或者字符串来表示时更加直观转换目的也更加明确。
  3. 每个状态类的职责单一明确,易于扩展。
  4. 封装性好,状态的转换在类的内部实现,外部调用就不需要知道类的内部是如何实现状态和行为的变换了。

(二)缺点

  1. 状态过多会引起类膨胀(事实上这也是大部分设计模式的通病)
  2. 对于支持状态切换的环境类(Context)违反了开闭原则,因为一旦状态修改或者中间要新增状态,则需要修改对应的源代码,否则会出现状态切换错误。
  3. 状态模式的结构与实现相对较为复杂,容易造成代码混乱。

七、与其他模式的区别

(一)状态模式与责任链模式

上面的状态模式的实现是有点和责任链模式相似,都是一条链去处理,可以这么说在某种场景下这两种模式可以互相替换,但是这两种模式也是有本质区别的。

  • 状态模式的下一个节点是各个状态对象已经了解的,而且状态的流转就是由内部进行流转,客户端无法决定。

  • 责任链模式的“链路”上的对象并不知道下一个节点处理人是谁,而是由客户端自行组装决定的。

(二)状态模式与策略模式

状态模式和策略模式都能用来消除大量的if/else场景,但是也有本质区别。

1.思想不同

  • 状态模式是: 将类的"状态"封装了起来,在运行时进行自动的转换,从而实现,类在同一行为下不同状态得都不同的个。它与策略模式的区别在于,这种转换是"自动","无意识"的。
  • 策略模式是:将类的变化的部分抽离出来,组合进类中,根据不同的子类替换实现动态改变行为(功能)

2.角色的不同

策略模式

  • Strategy: 定义所有支持的算法的公共接口抽象类.
  • ConcreteStrategy: 封装了具体的算法或行为,继承于Strategy
  • Context: 用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。

状态模式

  • State: 抽象状态类,定义一个接口以封装与context的一个状态相关的行为
  • ConcreteState: 具体状态,每一子类实现一个与Context的一个状态相关的行为
  • Context: 维护一个ConcreteState子类的实例,这个实例定义当前的状态。

3.环境角色的职责不同

  • 两者都有一个叫做Context环境角色的类,但区别很大,策略模式的环境角色只是一个委托作用,负责策略的替换;而状态模式的环境角色不仅仅是委托行为,它还具有记录状态变化的功能,与具体的状态类协作,共同完成状态切换行为随之切换的任务。

4.解决问题的重点不同

  • 策略模式旨在解决内部策略如何改变的问题,也就是将内部策略的改变对外界的影响降低到最小,使策略可以自由地切换;而状态模式旨在解决内在状态的改变而引起行为(功能)改变的问题,它的出发点是状态,封装状态而暴露行为(功能),一个对象的状态改变,从外界来看就好像是行为(功能)改变。
posted @ 2022-12-14 11:34  ImreW  阅读(80)  评论(0编辑  收藏  举报