简介
状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。
其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。
你还可将该方法应用在对象上。 假如你有一个计算任务调度服务平台。 任务可能会处于 创建
、 启动
和 已完成
等多种状态, 任务运行策略会在不同状态下的行为略有不同:
- 处于 启动时, 它会将文档转移到
完成/失败
中状态
- 处于 重启时, 它会将文档转移到启动状态
- 处于 停止时,它会转移到熔断状态
编码阶段(demo code)
下面是一个简单的类图,我们以此来进行推进demo。
步骤 1
创建一个接口。
1 2 3
| public interface State { public void doAction(Context context); }
|
步骤 2
创建实现接口的实体类。
StartState.java
1 2 3 4 5 6 7 8 9 10 11
| public class StartState implements State { public void doAction(Context context) { System.out.println("Player is in start state"); context.setState(this); } public String toString(){ return "Start State"; } }
|
StopState.java:
1 2 3 4 5 6 7 8 9 10 11
| public class StopState implements State { public void doAction(Context context) { System.out.println("Player is in stop state"); context.setState(this); } public String toString(){ return "Stop State"; } }
|
步骤 3
创建 Context 类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Context { private State state; public Context(){ state = null; } public void setState(State state){ this.state = state; } public State getState(){ return state; } }
|
步骤 4
使用 Context 来查看当状态 State 改变时的行为变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class StatePatternDemo { public static void main(String[] args) { Context context = new Context(); StartState startState = new StartState(); startState.doAction(context); System.out.println(context.getState().toString()); StopState stopState = new StopState(); stopState.doAction(context); System.out.println(context.getState().toString()); } }
|
步骤 5
执行程序,输出结果:
1 2 3 4
| Player is in start state Start State Player is in stop state Stop State
|
上面这些code已经完成了,有一些问题,下一步准备优化
Spring优化版本
上面的demo阶段有一些问题
- 无法融入到spring容器中
- 假如加入到spring容器中,涉及到的类都需要进行一遍注入?
1 2 3 4 5
| @Resource private StartState startState;
@Resource private StopState stopState;
|
问题也在此暴露了出来,无法真正的实现解耦
- 无法做熔断,可能会出现过多的try-catch,比如执行start失败后需要处理熔断,执行stop后需要处理重试
改进思路
状态设计模式适用于多种状态判断时,进行各状态解耦的前提下,还得注意保护自己的代码
- 首先并不推荐使用Spring的状态机,个人理解对代码的侵入性太强
- 简洁的change方式更能体现出业务代码,切划分更细
- 增加一个枚举,来进行参数的传递
- 所有的bean全部加入到spring容器中,做单例管理
- 增加一个类似于适配器的选择器,传递枚举、context来继续实现状态模式
- context需要改造,不应持有状态的对象。应该持有变量来进行规范
下面是改进后的类图
增加枚举,确定状态传递参数
枚举用来作为参数的传递,是本次改造重要的一环
1 2 3 4 5 6 7 8
| @Getter @AllArgsConstructor public enum StateEnum { START(1), STOP(2), RE_START(3); private int state; }
|
Context类进行改造
context改造后,仅作为参数类进行传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@Data @AllArgsConstructor @NoArgsConstructor public class Context {
private Long userId;
private StateEnum stateEnum; }
|
state类融入spring容器,改造
先把相关类加入到容器中
1 2 3 4 5 6 7 8 9 10
| @Service public class StartState implements State { }
@Service public class StopState implements State { }
|
State类增加hit函数,判定是否命中
给State类增加一个是否命中函数,相关实现类指定自己的枚举值进行eq
1 2 3 4 5 6 7 8 9 10
| public interface State {
boolean isHit(Context context);
}
|
下面再给各个实现类增加实现
StartState:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Service public class StartState implements State {
@Override public boolean isHit(Context context) { return StateEnum.START.equals(context.getStateEnum()); } }
|