设计模式的理解:状态模式(State) 和备忘录模式(Memento)
一、狀態模式? ?
? 狀態模式,允許對象在內部狀態發生改變時改變它的行為,對象看起來好像修改了它的類。它的實現方式和策略模式相似,目的都是對if...else語句進行優化,只不過,策略模式通過外部傳入枚舉、條件來決定選擇哪一種操作方式。策略模式中的枚舉、條件相當于狀態模式中的狀態。狀態不需要由外部傳入,而是隨著自身的操作來自動地變化。
?
?
例如類Context 包含以下的流程圖,context 有兩個方法run 和fallback,四種狀態,例如當狀態Ready執行一次run操作狀態變成了d式,允許對象在內部狀態發生改變時改變它的行為,對象看起來好像修改了它的類。它的實現方式和策略模式相似,目的都是對if...else語句進行優化,只不過,策略模式通過外部傳入枚舉、條件來決定選擇哪一種操作方式。策略模式中的枚舉、條件相當于狀態模式中的狀態。狀態不需要由外部傳入,而是隨著自身的操作來自動地變化。
?
?
例如類Context 包含以下的流程圖,context 有兩個方法run 和fallback,四種狀態,例如當狀態Ready執行一次run操作狀態變成了executing,當再執行run時就變成了完成狀態,如果執行fallback就變成了hangup狀態。?
?
本例目標是為了展示?2*100 ?的計算和輸出過程。
方法一
enum State{Ready,Executing,Finish,Hangup }class Context{State state;int result;public:void run(){if(state == Ready){result = 2;state = Executing;}else if(state == Executing){result *=100;state =Finish;}else if(state == Finish){cout<<"result:"<<result;result=0;state =Ready;}else if(state ==Hangup){state = Executing;}}void fallback(){if(state == Ready){state = Ready;result=0;}else if(state == Executing){state =Hangup;}else if(state == Finish){result /=100;state =Executing;}else if(state ==Hangup){state = Ready;result =2;}} }當操作方法發生需求變更時,方法一代碼這樣寫影響范圍就會覆蓋整個流程,代碼不易維護,不易擴展。如果增加狀態,那么枚舉要新增,run方法和fallback方法也要跟者新增,代碼會變得越來越臃腫。
方法二:利用狀態模式,把枚舉變成類對象
enum State{Ready,Executing,Finish,Hangup } /********狀態類,可用單例模式進行優化***********/ class IState{virtual State oprationRun(Context *)=0;virtual State oprationFallback(Context *)=0; }; class ReadyState:public IState{ public:virtual State oprationRun(Context * context){context->result=2;return Executing;}virtual State oprationFallback(Context * context){context->result=0;return Ready;} }; class ExecutingState:public IState{ public:virtual State oprationRun(Context * context){context->result *=100;return Finish;}virtual State oprationFallback(Context * context){return Hangup;} }; class FinishState:public IState{ public:virtual State oprationRun(Context * context){cout<<"result:"<< context->result;context->result =0;return Ready;}virtual State oprationFallback(Context * context){context->result /=100;return Executing;} }; class HangupState:public IState{ public:virtual State oprationRun(Context * context){return Executing;}virtual State oprationFallback(Context * context){context->result=2;return Ready;} };/*********Context自動地完成操作******************/ class Context{State state; //狀態屬性,這個屬性變化,操作也會動態地變化IState * iState; //狀態對象int result; private: void initIState(){switch(state){case Ready: iState =new ReadyState(); break;case Executing:iState =new ExecutingState(); break;case Finish: iState =new FinishState(); break;case Hangup: iState =new HangupState(); break;Default:....ERROR....} }public:Context(){state =Ready;result =0;}void run(){initIState();state =iState->oprationRun(this);}void fallback(){initIState();state =iState->oprationFallback(this);} }這樣的好處就是當變更狀態內部操作時,不需要改動Context方法。當新增一個狀態時,只需要新增一個狀態類和一個映射就可以,不需要變動其他狀態方法。這樣編碼結構清晰,誤操作的可能變小,變得更容易維護。
最后調用過程
void main(){Context context; //result =0 ,狀態為Readycontext.run(); //result =2 ,狀態從Ready變成Executing;context.run(); //result =200 ,狀態從Executing變成finish;context.run(); //輸出 200 ,狀態從finish變成Ready; result =0 }?
二、備忘錄模式
? ? ? ? ? ?備忘錄模式,在不破壞封裝性的前提下,捕獲對象內部的狀態,并將者著狀態放在外部進行保存(比如文件,數據庫)。方便以后對象恢復到原先的狀態。相當于游戲的存檔。
在模式中,具體實現的方式就是新增一個類,用來存儲原先對象重要的屬性。
繼續按照上述例子,新增備忘錄類和get/set備忘錄方法
enum State{Ready,Executing,Finish,Hangup } /********狀態類,可用單例模式進行優化***********/ class IState{virtual State oprationRun(Context *)=0;virtual State oprationFallback(Context *)=0; }; class ReadyState:public IState{ public:virtual State oprationRun(Context * context){context->result=2;return Executing;}virtual State oprationFallback(Context * context){context->result=0;return Ready;} }; class ExecutingState:public IState{ public:virtual State oprationRun(Context * context){context->result *=100;return Finish;}virtual State oprationFallback(Context * context){return Hangup;} }; class FinishState:public IState{ public:virtual State oprationRun(Context * context){cout<<"result:"<< context->result;context->result =0;return Ready;}virtual State oprationFallback(Context * context){context->result /=100;return Executing;} }; class HangupState:public IState{ public:virtual State oprationRun(Context * context){return Executing;}virtual State oprationFallback(Context * context){context->result=2;return Ready;} };/*********Context自動地完成操作******************/ class Context{State state; //狀態屬性,這個屬性變化,操作也會動態地變化IState * iState; //狀態對象int result; private: void initIState(){switch(state){case Ready: iState =new ReadyState(); break;case Executing:iState =new ExecutingState(); break;case Finish: iState =new FinishState(); break;case Hangup: iState =new HangupState(); break;Default:....ERROR....} }public:Context(){state =Ready;result =0;}void run(){initIState();state =iState->oprationRun(this);}void fallback(){initIState();state =iState->oprationFallback(this);}/****創建存檔和讀取存檔*****/ContextMemento createMemento(){return ContextMemento (state,result);}void setMemento(ContextMemento& cm){state = cm.oldstate;result = cm.oldresult;} }/**********備忘錄對象************/ class ContextMemento{ public: State oldstate; //狀態屬性,這個屬性變化,操作也會動態地變化int oldresult;ContextMemento (State s, int r){oldstate= s; oldresult=r;} } void main(){Context context; //result =0 ,狀態為Readycontext.run(); //result =2 ,狀態從Ready變成Executing;ContextMemento contextMemento = context.createMemento();context.run(); //result =200 ,狀態從Executing變成finish;context.setMemento(contextMemento ); //result =2 狀態為 Executingcontext.run(); //result =200 ,狀態從Executing變成finish;context.run();//輸出 200 ,狀態從finish變成Ready; result =0 }?
備忘錄的目的就是為了存檔,現如今,儲存/讀取對象有更方便的方式。備忘錄模式在如今有些過時。更有效的方式可以替代備忘錄模式,例如對象序列化,對象編碼等。但是備忘錄的思想還是沒變:
1)不破壞原對象的封裝性
2) 獲取原對象重要的屬性,并對這些屬性進行隱藏
?
總結
以上是生活随笔為你收集整理的设计模式的理解:状态模式(State) 和备忘录模式(Memento)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式理解:中介者模式(Mediato
- 下一篇: 设计模式的理解:组合模式 (Compos