状态设计模式的实践
简介
状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。

其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。
你还可将该方法应用在对象上。 假如你有一个计算任务调度服务平台。 任务可能会处于 创建 、 启动和 已完成等多种状态, 任务运行策略会在不同状态下的行为略有不同:
- 处于 启动时, 它会将文档转移到
完成/失败中状态 - 处于 重启时, 它会将文档转移到启动状态
- 处于 停止时,它会转移到熔断状态

编码阶段(demo code)
下面是一个简单的类图,我们以此来进行推进demo。

步骤 1
创建一个接口。
1 | public interface State { |
步骤 2
创建实现接口的实体类。
StartState.java
1 | public class StartState implements State { |
StopState.java:
1 | public class StopState implements State { |
步骤 3
创建 Context 类。
1 | public class Context { |
步骤 4
使用 Context 来查看当状态 State 改变时的行为变化。
1 | public class StatePatternDemo { |
步骤 5
执行程序,输出结果:
1 | Player is in start state |
上面这些code已经完成了,有一些问题,下一步准备优化
Spring优化版本
上面的demo阶段有一些问题
- 无法融入到spring容器中
- 假如加入到spring容器中,涉及到的类都需要进行一遍注入?
1 |
|
问题也在此暴露了出来,无法真正的实现解耦
- 无法做熔断,可能会出现过多的try-catch,比如执行start失败后需要处理熔断,执行stop后需要处理重试
改进思路
状态设计模式适用于多种状态判断时,进行各状态解耦的前提下,还得注意保护自己的代码
- 首先并不推荐使用Spring的状态机,个人理解对代码的侵入性太强
- 简洁的change方式更能体现出业务代码,切划分更细
- 增加一个枚举,来进行参数的传递
- 所有的bean全部加入到spring容器中,做单例管理
- 增加一个类似于适配器的选择器,传递枚举、context来继续实现状态模式
- context需要改造,不应持有状态的对象。应该持有变量来进行规范
下面是改进后的类图

增加枚举,确定状态传递参数
枚举用来作为参数的传递,是本次改造重要的一环
1 |
|
Context类进行改造
context改造后,仅作为参数类进行传递
1 |
|
state类融入spring容器,改造
先把相关类加入到容器中
1 |
|
State类增加hit函数,判定是否命中
给State类增加一个是否命中函数,相关实现类指定自己的枚举值进行eq
1 | public interface State { |
下面再给各个实现类增加实现
StartState:
1 |
|