当前位置:   article > 正文

大话设计模式 —— 第十六章《状态模式》C++ 代码实现_c++单一状态模式

c++单一状态模式

目录

定义

优点

缺点

使用场景


状态模式是一种行为型设计模式。当某个对象在不同状态下有不同行为时使用,在该模式中,我们将对象的不同状态 
定义成不同的类,在这些状态类下有它们各自的行为,然后在客户端调用 Context 类,而不需要显示地去设置各个状态之间的转换


定义


  • 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

该模式的本质是对象的状态改变时,会引起其行为的改变,从外部看就像该对象所对应的类的行为发生了改变一样。例如,电灯的开关,在灯的不同状态下(亮或灭),按下开关时,灯的行为是不一样的。或者说汽车,只有在车停下的时候才能打开车门,行驶的时候是不可以开门的。这就是状态的不同就会导致不同的行为。

状态模式UML图
  • 从UML来看,UML的结构似乎和策略模式是一模一样的,但是两种模式的本质却是完全不同的。策略模式中的策略(或者说是行为)是因为根据外界需要而使用不同的策略来完成需求;而状态模式中,是因为其自身状态改变,而影响了自身的一系列行为的改变。虽然这个状态的变更可能是外界引发的。
  • 抽象状态角色(State),负责定义各个状态有哪些行为,该抽象状态包含所有具体状态的方法。并且封装环境角色,帮助切换状态。
  • 具体状态角色(ConcreteState),实现具体状态下可以执行的行为,    每一个具体状态类必须完成两个职责:该类本状态下要做的事情,以及如何执行到其他具体状态类的状态。
  • 环境角色(Context) ,该角色是客户端要调用的接口,在该类内部维护一个ConcreteState子类的一个实例,可以负责具体状态的切换(客户端不知道状态的切换)。

用C++ 代码实现大话设计模式本章代码:

  1. #include<iostream>
  2. using namespace std;
  3. class State;
  4. class ForenoonState;
  5. class NoonState;
  6. class AfternonnState;
  7. class EveningState;
  8. class SleepingState;
  9. class RestState;
  10. class Work;
  11. // 抽象状态角色,负责定义各个状态有哪些行为,该抽象状态包含所有具体状态的方法。并且封装环境角色,帮助切换状态。
  12. class State
  13. {
  14. public:
  15. virtual void writeprogram(Work* w) = 0;
  16. virtual ~State() = default;
  17. };
  18. // Contex 角色,在该类内部维护一个ConcreteState子类的一个实例,可以负责具体状态的切换
  19. class Work
  20. {
  21. private:
  22. State* current;
  23. double m_hour;
  24. bool m_finish = false;
  25. public:
  26. Work();
  27. ~Work();
  28. void setHour(double hour) { m_hour = hour; }
  29. double getHour() { return m_hour; }
  30. void setFinish(bool finish) { m_finish = finish; }
  31. bool getFinish() { return m_finish; }
  32. void SetState(State* s)
  33. {
  34. delete current;
  35. current = s;
  36. }
  37. void WorkProgram()
  38. {
  39. current->writeprogram(this);
  40. }
  41. };
  42. // 下面都是具体的状态类,每一个具体状态类必须完成两个职责:该类本状态下要做的事情,以及如何执行到其他具体状态类的状态。
  43. class ForenoonState :public State
  44. {
  45. public:
  46. void writeprogram(Work* w)override;
  47. };
  48. class NoonState :public State
  49. {
  50. public:
  51. void writeprogram(Work* w)override;
  52. };
  53. class AfternoonState :public State
  54. {
  55. public:
  56. void writeprogram(Work* w)override;
  57. };
  58. class EveningState :public State
  59. {
  60. public:
  61. void writeprogram(Work* w)override;
  62. };
  63. class SleepingState :public State
  64. {// 睡眠状态
  65. public:
  66. void writeprogram(Work *w)override;
  67. };
  68. class RestState :public State
  69. {// 下班休息状态
  70. public:
  71. void writeprogram(Work *w)override;
  72. };
  73. Work::Work()
  74. {
  75. current = new ForenoonState();
  76. }
  77. Work::~Work()
  78. {
  79. delete current;
  80. }
  81. void ForenoonState::writeprogram(Work* w)
  82. {
  83. if (w->getHour() < 12)
  84. {
  85. cout << "当前时间:" << w->getHour() << "点,上午工作,精神百倍" << endl;
  86. }
  87. else
  88. {
  89. w->SetState(new NoonState());
  90. w->WorkProgram();
  91. }
  92. }
  93. void NoonState::writeprogram(Work* w)
  94. {
  95. if (w->getHour() < 13)
  96. {
  97. cout << "当前时间:" << w->getHour() << "点,吃午饭,睡午觉" << endl;
  98. }
  99. else
  100. {
  101. w->SetState(new AfternoonState());
  102. w->WorkProgram();
  103. }
  104. }
  105. void AfternoonState::writeprogram(Work* w)
  106. {
  107. if (w->getHour() < 17)
  108. {
  109. cout << "当前时间:" << w->getHour() << "点,下午状态还不错" << endl;
  110. }
  111. else
  112. {
  113. w->SetState(new EveningState());
  114. w->WorkProgram();
  115. }
  116. }
  117. void EveningState::writeprogram(Work* w)
  118. {
  119. if (w->getFinish())
  120. {
  121. w->SetState(new RestState());
  122. w->WorkProgram();
  123. }
  124. else
  125. {
  126. if (w->getHour() < 21)
  127. {
  128. cout << "当前时间:" << w->getHour() << "点,加班哦,疲惫至极 " << endl;
  129. }
  130. else
  131. {
  132. w->SetState(new SleepingState());
  133. w->WorkProgram();
  134. }
  135. }
  136. }
  137. void SleepingState::writeprogram(Work *w)
  138. {
  139. cout << "当前时间:" << w->getHour() << "点,不行了,睡着了 " << endl;
  140. }
  141. void RestState::writeprogram(Work *w)
  142. {
  143. cout << "当前时间:" << w->getHour() << "点,下班回家了 " << endl;
  144. }
  145. int main()
  146. {
  147. Work emergencyProjects;
  148. emergencyProjects.setHour(9);
  149. emergencyProjects.WorkProgram();
  150. emergencyProjects.setHour(10);
  151. emergencyProjects.WorkProgram();
  152. emergencyProjects.setHour(12);
  153. emergencyProjects.WorkProgram();
  154. emergencyProjects.setHour(13);
  155. emergencyProjects.WorkProgram();
  156. emergencyProjects.setHour(14);
  157. emergencyProjects.WorkProgram();
  158. emergencyProjects.setHour(17);
  159. emergencyProjects.WorkProgram();
  160. emergencyProjects.setFinish(false);
  161. emergencyProjects.setHour(19);
  162. emergencyProjects.WorkProgram();
  163. emergencyProjects.setHour(22);
  164. emergencyProjects.WorkProgram();
  165. system("pause");
  166. return 0;
  167. }

运行后截图:

可以看到,在客户端代码中,我们只需要调用Context类中方法即可,并不需要手动去改变状态,每执行一次方法就可以自动改变对象的状态,进而可以产生不同的行为,这就是状态模式。 


优点


  • 通过把各种状态判断逻辑分布到State的子类中,减少相互之间的依赖

在状态模式中,环境(Context)中不必出现大量的条件判断语句。环境(Context)实例所呈现的状态变得更加清晰、容易理解,提高代码的可维护性。

  • 如果不是有状态模式,一个对象需要在不同状态执行不同方法或者拥有不同特性的话,你可能需要在大量的 switch...case 或者 if...else 语句来根据不同状态执行不同方法,代码看起来就很复杂了

遵循设计原则

  • 每一个状态都是一个子类,符合单一职责原则,且当需要增加一个状态时,也是可以增加一个子类,需要修改一个状态时,也是修改一个子类即可。
  • 所有的状态都是一个子类,如果修改状态,只需要修改这个状态的子类即可,符合单一职责原则。且当需要增加一个状态时,也增加一个子类即可;需要修改一个状态时,也是修改一个子类即可。

封装性好

  • 状态的变换放置在类的内部实现,外界调用不知道内部的状态改变,只要调用其方法即可。

缺点


  • 由于所有的状态都是一个类,有的对象可能会有非常多的状态。随着状态的增加,系统类和对象个数也会增加。这个时候就使用状态模式就会导致类特别多,结构和实现会比较复杂,且不利于维护。如果使用不当将导致程序结构和代码的混乱。所以说,在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
  • 状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

使用场景


  • 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式。
  • 需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/421469
推荐阅读
相关标签
  

闽ICP备14008679号