状态模式(State Pattern),对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
**
状态模式组成如下:

Context(环境类) 定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换
State(抽象状态) 用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为
Concrete State(具体状态) 实现抽象状态所对应的行为,并且在需要的情况下进行状态切换

状态模式的优点

  1. 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”
  2. 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖
  3. 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换

状态模式的缺点

  1. 状态模式的使用必然会增加系统的类与对象的个数
  2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱
  3. 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码

状态模式使用场景

  1. 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式
  2. 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时

状态模式使用示例

使用状态模式模拟线程的状态转换。

分析:多线程存在 5 种状态,分别为新建状态、就绪状态、运行状态、阻塞状态和死亡状态,各个状态当遇到相关方法调用或事件触发时会转换到其他状态。

现在先定义一个抽象状态类(TheadState),然后为每个状态设计一个具体状态类,它们是新建状态(New)、就绪状态(Runnable )、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead),每个状态中有触发它们转变状态的方法,环境类(ThreadContext)中先生成一个初始状态(New),并提供相关触发方法:

  1. public class StatePattern {
  2. /**
  3. * 状态模式的关键设计思想在于状态切换,我们引入一个ThreadContext完成状态切换
  4. */
  5. static class ThreadContext {
  6. private ThreadState threadState;
  7. ThreadContext() {
  8. threadState = new New();
  9. }
  10. public void setThreadState(ThreadState threadState) {
  11. this.threadState = threadState;
  12. }
  13. public ThreadState getThreadState() {
  14. return threadState;
  15. }
  16. void start() {
  17. ((New) threadState).start(this);
  18. }
  19. public void getCPU() {
  20. ((Runnable) threadState).getCPU(this);
  21. }
  22. public void suspend() {
  23. ((Running) threadState).suspend(this);
  24. }
  25. public void stop() {
  26. ((Running) threadState).stop(this);
  27. }
  28. public void resume() {
  29. ((Blocked) threadState).resume(this);
  30. }
  31. }
  32. abstract static class ThreadState {
  33. protected String stateName;
  34. }
  35. static class New extends ThreadState {
  36. public New() {
  37. stateName = "新建状态";
  38. System.out.println("当前线程处于:新建状态.");
  39. }
  40. public void start(ThreadContext context) {
  41. System.out.print("调用start()方法-->");
  42. if (stateName.equals("新建状态")) {
  43. context.setThreadState(new Runnable());
  44. } else {
  45. System.out.println("当前线程不是新建状态,不能调用start()方法.");
  46. }
  47. }
  48. }
  49. //具体状态类:就绪状态
  50. static class Runnable extends ThreadState {
  51. public Runnable() {
  52. stateName = "就绪状态";
  53. System.out.println("当前线程处于:就绪状态.");
  54. }
  55. public void getCPU(ThreadContext context) {
  56. System.out.print("获得CPU时间-->");
  57. if (stateName.equals("就绪状态")) {
  58. context.setThreadState(new Running());
  59. } else {
  60. System.out.println("当前线程不是就绪状态,不能获取CPU.");
  61. }
  62. }
  63. }
  64. //具体状态类:运行状态
  65. static class Running extends ThreadState {
  66. public Running() {
  67. stateName = "运行状态";
  68. System.out.println("当前线程处于:运行状态.");
  69. }
  70. public void suspend(ThreadContext context) {
  71. System.out.print("调用suspend()方法-->");
  72. if (stateName.equals("运行状态")) {
  73. context.setThreadState(new Blocked());
  74. } else {
  75. System.out.println("当前线程不是运行状态,不能调用suspend()方法.");
  76. }
  77. }
  78. public void stop(ThreadContext context) {
  79. System.out.print("调用stop()方法-->");
  80. if (stateName.equals("运行状态")) {
  81. context.setThreadState(new Dead());
  82. } else {
  83. System.out.println("当前线程不是运行状态,不能调用stop()方法.");
  84. }
  85. }
  86. }
  87. //具体状态类:阻塞状态
  88. static class Blocked extends ThreadState {
  89. public Blocked() {
  90. stateName = "阻塞状态";
  91. System.out.println("当前线程处于:阻塞状态.");
  92. }
  93. public void resume(ThreadContext context) {
  94. System.out.print("调用resume()方法-->");
  95. if (stateName.equals("阻塞状态")) {
  96. context.setThreadState(new Runnable());
  97. } else {
  98. System.out.println("当前线程不是阻塞状态,不能调用resume()方法.");
  99. }
  100. }
  101. }
  102. //具体状态类:死亡状态
  103. static class Dead extends ThreadState {
  104. public Dead() {
  105. stateName = "死亡状态";
  106. System.out.println("当前线程处于:死亡状态.");
  107. }
  108. }
  109. public static void main(String[] args) {
  110. ThreadContext context = new ThreadContext();
  111. context.start();
  112. context.getCPU();
  113. context.suspend();
  114. context.resume();
  115. context.getCPU();
  116. context.stop();
  117. }
  118. }

程序运行结果如下:

:::success 当前线程处于:新建状态.
调用start()方法—>当前线程处于:就绪状态.
获得CPU时间—>当前线程处于:运行状态.
调用suspend()方法—>当前线程处于:阻塞状态.
调用resume()方法—>当前线程处于:就绪状态.
获得CPU时间—>当前线程处于:运行状态.
调用stop()方法—>当前线程处于:死亡状态. :::