動機(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的子類之間,來減少相互間的依賴。當一個對象的行為取決於它的狀態,並且它必須在運行時根據狀態改變它的行為時,就可以考慮使用狀態模式了。
優點:將與特定狀態有關的行為局部化,並且將不同狀態的行為分割開來。