状态模式(State Pattern),对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
**
状态模式组成如下:
| Context(环境类) | 定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换 |
|---|---|
| State(抽象状态) | 用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为 |
| Concrete State(具体状态) | 实现抽象状态所对应的行为,并且在需要的情况下进行状态切换 |
状态模式的优点
- 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”
- 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖
- 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换
状态模式的缺点
- 状态模式的使用必然会增加系统的类与对象的个数
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱
- 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码
状态模式使用场景
- 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式
- 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时
状态模式使用示例
使用状态模式模拟线程的状态转换。
分析:多线程存在 5 种状态,分别为新建状态、就绪状态、运行状态、阻塞状态和死亡状态,各个状态当遇到相关方法调用或事件触发时会转换到其他状态。
现在先定义一个抽象状态类(TheadState),然后为每个状态设计一个具体状态类,它们是新建状态(New)、就绪状态(Runnable )、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead),每个状态中有触发它们转变状态的方法,环境类(ThreadContext)中先生成一个初始状态(New),并提供相关触发方法:
public class StatePattern {/*** 状态模式的关键设计思想在于状态切换,我们引入一个ThreadContext完成状态切换*/static class ThreadContext {private ThreadState threadState;ThreadContext() {threadState = new New();}public void setThreadState(ThreadState threadState) {this.threadState = threadState;}public ThreadState getThreadState() {return threadState;}void start() {((New) threadState).start(this);}public void getCPU() {((Runnable) threadState).getCPU(this);}public void suspend() {((Running) threadState).suspend(this);}public void stop() {((Running) threadState).stop(this);}public void resume() {((Blocked) threadState).resume(this);}}abstract static class ThreadState {protected String stateName;}static class New extends ThreadState {public New() {stateName = "新建状态";System.out.println("当前线程处于:新建状态.");}public void start(ThreadContext context) {System.out.print("调用start()方法-->");if (stateName.equals("新建状态")) {context.setThreadState(new Runnable());} else {System.out.println("当前线程不是新建状态,不能调用start()方法.");}}}//具体状态类:就绪状态static class Runnable extends ThreadState {public Runnable() {stateName = "就绪状态";System.out.println("当前线程处于:就绪状态.");}public void getCPU(ThreadContext context) {System.out.print("获得CPU时间-->");if (stateName.equals("就绪状态")) {context.setThreadState(new Running());} else {System.out.println("当前线程不是就绪状态,不能获取CPU.");}}}//具体状态类:运行状态static class Running extends ThreadState {public Running() {stateName = "运行状态";System.out.println("当前线程处于:运行状态.");}public void suspend(ThreadContext context) {System.out.print("调用suspend()方法-->");if (stateName.equals("运行状态")) {context.setThreadState(new Blocked());} else {System.out.println("当前线程不是运行状态,不能调用suspend()方法.");}}public void stop(ThreadContext context) {System.out.print("调用stop()方法-->");if (stateName.equals("运行状态")) {context.setThreadState(new Dead());} else {System.out.println("当前线程不是运行状态,不能调用stop()方法.");}}}//具体状态类:阻塞状态static class Blocked extends ThreadState {public Blocked() {stateName = "阻塞状态";System.out.println("当前线程处于:阻塞状态.");}public void resume(ThreadContext context) {System.out.print("调用resume()方法-->");if (stateName.equals("阻塞状态")) {context.setThreadState(new Runnable());} else {System.out.println("当前线程不是阻塞状态,不能调用resume()方法.");}}}//具体状态类:死亡状态static class Dead extends ThreadState {public Dead() {stateName = "死亡状态";System.out.println("当前线程处于:死亡状态.");}}public static void main(String[] args) {ThreadContext context = new ThreadContext();context.start();context.getCPU();context.suspend();context.resume();context.getCPU();context.stop();}}
程序运行结果如下:
:::success
当前线程处于:新建状态.
调用start()方法—>当前线程处于:就绪状态.
获得CPU时间—>当前线程处于:运行状态.
调用suspend()方法—>当前线程处于:阻塞状态.
调用resume()方法—>当前线程处于:就绪状态.
获得CPU时间—>当前线程处于:运行状态.
调用stop()方法—>当前线程处于:死亡状态.
:::
