1. 定义
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变 时改变其行为
2. 类型
行为型(behavioral)
3.介绍
优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点: 1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
使用场景:
- 行为随状态改变而改变的场景。
- 条件、分支语句的代替者。
注意事项:在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
4.结构
状态模式包含以下主要角色。
- 环境(Context)角色:也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为。
5.代码
5.1 抽象状态类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public abstract class LiftState { protected Context context; public void setContext(Context context) { this.context = context; } public abstract void open(); public abstract void close(); public abstract void run(); public abstract void stop(); }
|
5.2 状态机类
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| package state;
public class StateMachine {
public final OpeningState openingState; public final ClosingState closingState; public final RunningState runningState; public final StoppingState stoppingState;
public StateMachine() { openingState = new OpeningState(); closingState = new ClosingState(); runningState = new RunningState(); stoppingState = new StoppingState(); }
public class OpeningState extends LiftState { @Override public void open() { System.out.println("电梯门开启..."); }
@Override public void close() { super.context.setLiftState(closingState); super.context.getLiftState().close(); }
@Override public void run() { }
@Override public void stop() { } }
public class RunningState extends LiftState { @Override public void open() { }
@Override public void close() { }
@Override public void run() { System.out.println("电梯正在运行..."); }
@Override public void stop() { super.context.setLiftState(stoppingState); super.context.stop(); } }
public class StoppingState extends LiftState { @Override public void open() { super.context.setLiftState(openingState); super.context.getLiftState().open(); }
@Override public void close() { super.context.setLiftState(closingState); super.context.getLiftState().close(); }
@Override public void run() { super.context.setLiftState(runningState); super.context.getLiftState().run(); }
@Override public void stop() { System.out.println("电梯停止了..."); } }
public class ClosingState extends LiftState { @Override public void close() { System.out.println("电梯门关闭..."); }
@Override public void open() { super.context.setLiftState(openingState); super.context.open(); }
@Override public void run() { super.context.setLiftState(runningState); super.context.run(); }
@Override public void stop() { super.context.setLiftState(stoppingState); super.context.stop(); } } }
|
5.3 环境类
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
| package state;
public class Context {
private LiftState liftState;
public LiftState getLiftState() { return this.liftState; }
public void setLiftState(LiftState liftState) { this.liftState = liftState; this.liftState.setContext(this); }
public void open() { this.liftState.open(); }
public void close() { this.liftState.close(); }
public void run() { this.liftState.run(); }
public void stop() { this.liftState.stop(); } }
|
5.4 测试类
1 2 3 4 5 6 7 8 9 10 11
| public class Main { public static void main(String[] args) { Context context = new Context(); StateMachine stateMachine = new StateMachine(); context.setLiftState(stateMachine.runningState); context.open(); context.close(); context.run(); context.stop(); } }
|
6.技术要点总结
- 必须要有一个Context类,这个类持有State接口,负责保持并切换当前的状态。
- 状态模式没有定义在哪里进行状态转换,本例是在具体的State类中转换
当使用Context类切换状态时,状态类之间互相不认识,他们直接的依赖关系应该由客户端负责。
当使用具体的State类切换时,状态直接就可能互相认识,一个状态执行完就自动切换到了另一个状态去了