动机(Motivation)
- 对象状态如果改变,其行为也会随之而发生变化,比如文档处于只读状态,其支持的行为和读写状态支持的行为就可能完全不同。
- 如何在运行时根据对象的状态来透明地改变对象的行为?
模式定义
允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。 ——《设计模式》GoF
状态模型,就是当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
要点总结
- State模式将所有与一个特定状态相关的行为都放入一个State的子对象中,在对象状态切换时,切换相应的对象; 但同时维持State的接口,这样实现了具体操作与状态转换之间的解耦。
- 转换是原子性的
- 与Strategy模式类似
结构(Structure)
看着这个类图好像和策略模式的UML图似乎相同?
https://www.cnblogs.com/wkfvawl/p/12453747.html
确实是这样的,这两种模式在结构上是相同的,但意图却完全不一样,策略模式是让用户指定更换的策略算法,而状态模式是状态在满足一定条件下的自动更换,用户无法指定状态,最多只能设置初始状态。
这里解释还是有点抽象,我在知乎上找到了一个生动形象的例子,虽然有点污,但话糙理不糙,大家可以看一下。
https://www.zhihu.com/question/23693088
基本代码
#include <iostream> using namespace std; class Context; class State { // 抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为 public: virtual void Handle(Context* c) = 0; virtual ~State() {} }; class Context { // 维护一个ConcreteState子类的实例,这个实例定义为当前状态 private: State* state; public: Context(State* s) { state = s; } void Request() { // // 对请求做处理,并设置下一状态 state->Handle(this); } void SetState(State* s) { state = s; } }; // 具体状态类,每一个字类实现与Context的一个状态相关行为 class ConcreteStateA : public State { public: void Handle(Context* c); }; class ConcreteStateB : public State { public: void Handle(Context* c); }; class ConcreteStateC : public State { public: void Handle(Context* c); }; void ConcreteStateA::Handle(Context* c) { cout << "ConcreteStateA" << endl; c->SetState(new ConcreteStateB()); } void ConcreteStateB::Handle(Context* c) { cout << "ConcreteStateB" << endl; c->SetState(new ConcreteStateC()); } void ConcreteStateC::Handle(Context* c) { cout << "ConcreteStateC" << endl; c->SetState(new ConcreteStateA()); } int main() { State* s = new ConcreteStateA(); Context* c = new Context(s); c->Request(); // ConcreteStateA 切换状态 c->Request(); // ConcreteStateB c->Request(); // ConcreteStateC delete s; delete c; return 0; }
应用场景
状态模式通过把各种状态转换转移逻辑分布到State的子类之间,来减少相互间的依赖。当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式了。
优点:将与特定状态有关的行为局部化,并且将不同状态的行为分割开来。