C++设计模式 之 “状态变化” 模式:State、Memento
“状态变化”模式
在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式为这一问题提供了一种解决方案。
典型模式
# state
# memento
Part 1 State 状态模式
动机
#在软件构建过程中,某些对象的状态如果改变,其行为也会随之而变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
#如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?
#避免代码的坏味道——Long Method
模式定义
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。——《设计模式》GoF
结构
结构 from 《大话设计模式》
代码 未使用State模式 from 《大话设计模式》
1 void work(int clock, TASK_FINISH task) { 2 if (clock < 12) 3 { 4 cout << "上午"<<endl; 5 } 6 else if (clock < 13) 7 { 8 cout << "中午" << endl; 9 } 10 else if (clock < 17) 11 { 12 cout << "下午" << endl; 13 } 14 else 15 { 16 if (task == true) 17 { 18 cout << "下班" << endl; 19 } 20 else 21 { 22 if (clock < 21) 23 { 24 cout << "晚上,加班" << endl; 25 } 26 27 cout << "好累,睡着了" << endl; 28 } 29 } 30 } 31 32 int main() { 33 34 work(9, false); 35 work(12, false); 36 work(15, false); 37 work(18, false); 38 39 return 0; 40 }
代码 State模式 from 《大话设计模式》
1 #include <string> 2 #include <iostream> 3 4 using namespace std; 5 6 struct Context; 7 struct State { 8 virtual void work(Context c) = 0; 9 }; 10 11 struct Context { 12 bool taskFinish = false; 13 unsigned clock = 6; 14 State* _state; 15 void work() { this->_state->work(*this); } 16 }; 17 18 struct SleepState : public State { 19 virtual void work(Context c) override { 20 cout << "sleeping..." << endl; 21 } 22 }; 23 24 struct EveningState : public State { 25 virtual void work(Context c) override { 26 if (c.taskFinish == true) 27 cout << "back home" << endl; 28 else 29 { 30 if (c.clock < 21) 31 cout << "evening" << endl; 32 else 33 c._state = new SleepState(); 34 } 35 } 36 }; 37 38 struct AfternoonState : public State { 39 virtual void work(Context c) override { 40 if (c.clock < 17) 41 cout << "afternoon" << endl; 42 else 43 c._state = new EveningState(); 44 } 45 }; 46 47 struct NoonState : public State { 48 virtual void work(Context c) override { 49 if (c.clock < 13) 50 cout << "noon" << endl; 51 else 52 c._state = new AfternoonState(); 53 } 54 }; 55 56 struct ForenoonState : public State { 57 virtual void work(Context c) override { 58 if (c.clock < 12) 59 cout << "forenoon" << endl; 60 else 61 c._state = new NoonState(); 62 } 63 }; 64 65 int main() { 66 Context project; 67 project._state = new ForenoonState(); 68 69 project.work(); 70 71 project.clock = 12; 72 project.work(); 73 74 project.clock = 14; 75 project.work(); 76 77 project.clock = 18; 78 project.work(); 79 80 return 0; 81 }
要点总结
#State模式将所有与一个特定状态相关的行为都放入一个State的子类对象中,在对象状态切换时,切换相应的对象;但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。
#为不同的状态引入不同的对象,使得状态转化变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换时原子性的——即要么彻底转换过来,要么不转换。
#如果State对象没有实例变量,那么各个上下文可以共享同一个State对象,从而节省对象开销。
智慧在街市上呼喊,在宽阔处发声。