首页 > 代码库 > 状态模式
状态模式
状态模式
1. 概述
状态模式,就是将对象的状态和对应状态下的行为分离开来,不再是简单的if…else或switch…case分支结构了,而是每一个状态都对应一个类,一个类集中管理一个状态;在多状态的情况下,简化了程序的维护和管理,让程序结构简明化,同时也易于扩展。
2. 解决的问题
当控制一个对象状态转换的条件表达式过于复杂时的情况。
3. 模式中的角色
1) 上下文环境(Context):定义了客户程序所需接口并维护一个具体状态角色实例,将与状态相关的操作委托给当前的ConcreteState对象处理。
2) 抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。
3) 具体状态(Concrete State):实现抽象状态定义的接口。
4. 优点
1) 状态模式将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
2) 所有状态相关的代码都存在于某个ConcereteState中,所以通过定义新的子类很容易地增加新的状态和转换。
3) 状态模式通过把各种状态转移逻辑分不到State的子类之间,来减少相互间的依赖。
5. 缺点
1) 导致较多的ConcreteState子类
6. 适用场景
下面是GOF在《设计模式》中给出的状态模式的适用情况:
1) 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
2) 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
7. 与策略模式的比较
下面是策略模式和方法模式的UML图
二者外表一样,只是二者的关注点不一样:
1) 策略模式关注行为的变化,但归根结底只有一个行为,变化的只是行为的实现。客户不关注这些.当新增变化时对客户可以没有任何影响。
2) 状态模式同样关注行为的变化,但这个变化是由状态来驱动,一般来说每个状态和行为都不同。客户需要关注新增的状态或行为与已有的不同。
状态模式一个形象的比喻是”饱了睡,饿了吃”.在这里”饱和饿”是两种状态,”睡和吃”是两种行为.
8.代码实现
1)用if...else的情况
1 typedef enum tagState 2 { 3 state, 4 state1, 5 state2 6 }State; 7 8 void Action(State actionState) 9 {10 if (actionState == state)11 {12 // DoSomething13 }14 else if (actionState == state1)15 {16 // DoSomething17 }18 else if (actionState == state2)19 {20 // DoSomething21 }22 else23 {24 // DoSomething25 }26 }
2)用状态模式表现--分离状态和行为
1 #include <iostream> 2 using namespace std; 3 4 class Context; 5 class State 6 { 7 public: 8 virtual void Handle(Context *pContext) = 0; 9 };10 11 class ConcreteStateA : public State12 {13 public:14 virtual void Handle(Context *pContext)15 {16 cout<<"I am concretestateA."<<endl;17 }18 };19 class ConcreteStateB : public State20 {21 public:22 virtual void Handle(Context *pContext)23 {24 cout<<"I am concretestateB."<<endl;25 }26 };27 28 class Context29 {30 public:31 Context(State *pState) : m_pState(pState){}32 void Request()33 {34 if (m_pState)35 {36 m_pState->Handle(this);37 }38 }39 void ChangeState(State *pState)40 {41 m_pState = pState;42 }43 private:44 State *m_pState;45 };46 47 int main()48 {49 State *pStateA = new ConcreteStateA();50 State *pStateB = new ConcreteStateB();51 Context *pContext = new Context(pStateA);52 53 pContext->Request();54 pContext->ChangeState(pStateB);55 pContext->Request();56 57 delete pContext;58 delete pStateB;59 delete pStateA;60 }
3)状态模式--旋转开关
"一般的状态判断"如:
if (which==1) state="hello";
else if (which==2) state="hi";
else if (which==3) state="bye";
如果改成:
if (state.euqals("bye")) state="hello";
else if (state.euqals("hello")) state="hi";
else if (state.euqals("hi")) state="bye";
这就是 "开关切换状态",是将state的状态从"hello"切换到"hi",再切换到""bye";在切换到"hello",好象一个旋转开关,这种状态改变就可以使用State模式了.
.h文件:
1 class Context; 2 class State 3 { 4 public: 5 virtual void Handle(Context* pContext)=0; 6 }; 7 8 class ConcreteStateA : public State 9 {10 public:11 virtual void Handle(Context* pContext);12 };13 14 class ConcreteStateB : public State15 {16 public:17 virtual void Handle(Context* pContext);18 };19 20 class ConcreteStateC : public State21 {22 public:23 virtual void Handle(Context* pContext);24 };25 26 class Context27 {28 public:29 Context(State* pState): m_pState(pState){}30 void Request()31 {32 if(m_pState)33 {34 m_pState->Handle(this);35 }36 }37 void ChangeState(State* pState)38 {39 m_pState = pState;40 }41 42 private:43 State* m_pState;44 };
.cpp文件
1 //执行该状态的行为并改变状态 2 void ConcreteStateA::Handle(Context* pContext) 3 { 4 cout << "ConcreteStateA" << endl; 5 pContext->ChangeState(new ConcreteStateB()); 6 } 7 8 //执行该状态的行为并改变状态 9 void ConcreteStateB::Handle(Context* pContext)10 {11 cout << "ConcreteStateB" << endl;12 pContext->ChangeState(new ConcreteStateC());13 }14 15 //执行该状态的行为并改变状态16 void ConcreteStateC::Handle(Context* pContext)17 {18 cout << "ConcreteStateC" << endl;19 pContext->ChangeState(new ConcreteStateA());20 }
客户端:
1 #include "State.h" 2 3 int main() 4 { 5 State* pState = new ConcreteStateA(); 6 Context* pContext = new Context(pState); 7 pContext->Request(); 8 pContext->Request(); 9 pContext->Request();10 pContext->Request();11 pContext->Request();12 return 0;13 }
状态模式