设计模式之状态模式
定义
状态模式 (State Pattern)允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类,类的行为随着它的状态改变而改变。
- 对象有自己的状态
- 不同状态下执行的逻辑不一样
- 用来减少if…else子句
生活中的例子
1)等红绿灯的时候,红绿灯的状态和行人汽车的通行逻辑是有关联的:
- 红灯亮:行人通行,车辆等待;
- 绿灯亮:行人等待,车辆通行;
- 黄灯亮:行人等待,车辆等待;
2)下载文件的时候,就有好几个状态;比如下载验证、下载中、暂停下载、下载完毕、失败,文件在不同状态下表现的行为也不一样,比如
- 下载中时显示可以暂停下载和下载进度,
- 下载失败时弹框提示并询问是否重新下载等等。
类图
在这些场景中,有以下特点:
- 对象有有限多个状态,且状态间可以相互切换;
- 各个状态和对象的行为逻辑有比较强的对应关系,即在不同状态时,对应的处理逻辑不一样;
在状态模式结构图中包含如下几个角色:
Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类 State 的实例,这个实例定义当前状态,在具体实现时,它是一个 State 子类的对象。
State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
代码实现
大多人的写法
1 |
|
存在的问题
- show违反开放-封闭原则
- show方法(胖函数)逻辑太多太复杂
- 颜色状态切换不明显
- 过多的 if/else 让代码不可维护
优化一
1 |
|
优化二
1 |
|
应用场景
- 操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态,那么可以使用状态模式来将分支的处理分散到单独的状态类中;
- 对象的行为随着状态的改变而改变,那么可以考虑状态模式,来把状态和行为分离,虽然分离了,但是状态和行为是对应的,再通过改变状态调用状态对应的行为;
Promise
1 |
|
React导航
1 |
|
有限状态机
- 事物拥有多种状态,任一时间只会处于一种状态不会处于多种状态;
- 动作可以改变事物状态,一个动作可以通过条件判断,改变事物到不同的状态,但是不能同时指向多个状态,一个时间,就一个状态
- 状态总数是有限的;
- javascript-state-machine
- form:当前行为从哪个状态来
- to:当前行为执行完会过渡到哪个状态
- name:当前行为的名字
- fsm.can(t) - return true 如果过渡方法t可以从当前状态触发
- fsm.cannot(t) - return true 如果当前状态下不能发生过渡方法t
- fsm.transitions() - 返回从当前状态可以过渡到的状态的列表
- fsm.allTransitions() - 返回所有过渡方法的列表
- fsm.allStates() - 返回状态机有的所有状态的列表
- onBefore 在特定动作TRANSITION前触发
- onLeaveState 离开任何一个状态的时候触发
- onEnter 进入一个特定的状态STATE时触发
- onLeave 在离开特定状态STATE时触发
- onTransition 在任何动作发生期间触发
- onEnterState 当进入任何状态时触发
- on onEnter的简写
- onAfterTransition 任何动作触发后触发
- onAfter 在特定动作TRANSITION后触发
- on onAfter的简写
1 |
|
状态模式的优缺点
状态模式的优点:
- 结构相比之下清晰,避免了过多的 switch-case 或 if-else 语句的使用,避免了程序的复杂性提高系统的可维护性;
- 符合开闭原则,每个状态都是一个子类,增加状态只需增加新的状态类即可,修改状态也只需修改对应状态类就可以了;
- 封装性良好,状态的切换在类的内部实现,外部的调用无需知道类内部如何实现状态和行为的变换。
状态模式的缺点:
- 引入了多余的类,每个状态都有对应的类,导致系统中类的个数增加。
设计模式之状态模式
https://retech-fe.github.io/blog/2022/10/02/design-pattern-state/