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