“状态变化”模式
在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?“状态变化”模式应运而生。
典型模式 :State、 Memento
State 状态模式
在实际开发中,经常会遇到,一个对象有多种状态,在每一个状态下,都有不同的行为。如下:
1 typedef enum tagState 2 { 3 state0, 4 state1, 5 state2 6 }State; 7 8 //根据不同的state执行不同的DoSomrthing,就实际上相当于不同的Handle 9 void Handle(State state) 10 { 11 if (state == state0){ 12 // DoSomethingA 13 } else if (state == state1){ 14 // DoSomethingB 15 } else if (state == state2){ 16 // DoSomethingC 17 }else { 18 // DoSomethingD 19 } 20 } 21 22 //等效于根据不同的state调用不同的Handle 23 void Handle(state0) { //Do somethingA } 24 void Handle(state1) { //Do somethingB } 25 void Handle(state2) { //Do somethingC } 26 void Handle(other) { //Do somethingD }
每当新增状态时,就需要添加if-else分支,修改原来的代码,违反“开闭原则”,而且大量的分支结构,使得代码难以理解与维护。
动机
- 在软件构建过程中,某些对象的状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
- 如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转换之间引入紧耦合?
定义
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。 ——《设计模式》GOF
有了状态模式之后,可以解决随着状态增加而出现的多分支结构,将状态处理分散到各个状态子类中去,每个子类处理一种状态,因而使得状态的处理和转换变得清晰明确。
结构
Context:定义客户端感兴趣的接口,并且维护一个ConcreteState子类的实例,这个实例定义当前状态;
State:定义一个接口以封装与Context的一个特定状态相关的行为;
ConcreteState A/B:每一个子类实现一个与Context的一个状态相关的行为。
它们之间的协作步骤:
- Context将与状态相关的请求委托给当前的ConcreteState对象处理;
- Context可以将自身作为一个参数传递给处理该请求的状态对象。这使得状态对象可以在必要时访问Context;
- Context是客户使用的主要接口。客户可用状态对象来配置一个Context,一旦一个Context配置完毕,它的客户不再需要直接与状态对象打交道。
代码实现:
1 #include <iostream> 2 using namespace std; 3 4 class Context; 5 6 //状态基类,为不同的状态规范统一的接口,当然可以有Handle1,Handle2... 7 class State { 8 public: 9 virtual void Handle(Context* pContext) = 0; 10 }; 11 12 //如最开始的实例代码,将if-else拆散为不同状态下的Handle处理函数 13 class ConcreteStateA : public State { 14 public: 15 virtual void Handle(Context* pContext) { cout << "I am concreteStateA "; } 16 }; 17 18 class ConcreteStateB : public State { 19 public: 20 virtual void Handle(Context* pContext) { cout << "I am concreteStateB "; } 21 }; 22 23 //客户使用的主要接口。用状态对象来配置一个Context 24 class Context { 25 public: 26 Context(State* pState) : m_pState(pState) {} 27 28 //根据多态的特性会实际调用到指定状态的处理函数 29 void Request() { 30 if (m_pState) { 31 m_pState->Handle(this); 32 } 33 } 34 35 void ChangState(State* pState) { m_pState = pState; } 36 37 private: 38 State* m_pState; 39 }; 40 41 int main() { 42 State* pStateA = new ConcreteStateA(); 43 State* pStateB = new ConcreteStateB(); 44 Context* pContext = new Context(pStateA); 45 pContext->Request(); 46 pContext->ChangState(pStateB); 47 pContext->Request(); 48 49 delete pContext; 50 delete pStateB; 51 delete pStateA; 52 53 return 0; 54 }
总结
状态模式是利用多态的动态绑定特性消除了if-else的分支结构,将对象的状态与对应状态下的行为分离开来,每一个状态对应一个类,一个类集中管理一个状态,在多状态的情况下,简化程序的结构,易于扩展。
参考: