命令模式的應用之可撤銷/恢復操作的計算器
阿新 • • 發佈:2019-02-12
深度理解命令模式
(1)引數化配置:用不同的命令物件,去引數化配置客戶的請求。
(2)可撤銷的操作:
①補償式(反操作式):如被撤銷的操作是加的功能,那麼反操作就是減的功能。
②儲存恢復式:把操作前的狀態記錄下來,然後要撤銷操作時就直接恢復回去就可以了。(該種方式會放到備忘錄模式中進行講解)
【程式設計實驗】可撤銷/恢復操作的計算器
//宣告檔案
//********************************************************************************************* //行為型模式:命令模式 //場景:計算器(可撤銷的計算) #include <iostream> #include <string> #include <list> using namespace std; //***************************************Receiver******************* //操作運算的介面 //運算類,真正實現加減法運算(具體的接收者) class CCalculator{ private: int iResult; public: void SetResult(int result); int GetResult(); void Add(int num); void Sub(int num); }; //*************************Command*********************** //命令介面,支援可撤銷操作 class CCalcCmd{ public: virtual void Execute() = 0;//執行命令的操作 virtual void Undo() = 0; //執行撤銷的操作 }; //具體的加法命令 class CAddCmd : public CCalcCmd{ private://持有具體執行計算的物件(命令的接收者) CCalculator* pCalc; int iNum;//要加上的資料 public: CAddCmd(CCalculator* calc, int num); void Execute(); void Undo(); }; //具體的減法命令 class CSubCmd : public CCalcCmd{ private://持有具體執行計算的物件(命令的接收者) CCalculator* pCalc; int iNum; //要減去的資料 public: CSubCmd(CCalculator* calc, int num); void Execute(); void Undo(); }; //*****************************Invoker************************************ //計算器類,計算器上有加法按鈕和減法按鈕 class CController{ private: CCalcCmd* pAddCmd;//加法命令物件 CCalcCmd* pSubCmd; //減法命令物件 list<CCalcCmd*> lstUndo; //命令的操作歷史記錄,在撤銷的時候用 list<CCalcCmd*> lstRedo; //命令被撤銷的歷史記錄,在恢復時使用 public: CController(CCalcCmd* addcmd, CCalcCmd* subcmd); void SetAddCmd(CCalcCmd* addcmd); void SetSubCmd(CCalcCmd* subcmd); //提供給客戶使用,執行加法, 減法功能, 把操作記錄到歷史記錄裡面 void Add(); void Sub(); void Undo(); void Redo(); };
//實現檔案
//***************************************Receiver******************* //操作運算的介面 //運算類,真正實現加減法運算(具體的接收者) void CCalculator::SetResult(int result){iResult = result;} int CCalculator::GetResult(){return iResult;} void CCalculator::Add(int num){ iResult += num;} void CCalculator::Sub(int num){ iResult -= num;} //*************************Command*********************** //命令介面,支援可撤銷操作 //具體的加法命令 CAddCmd::CAddCmd(CCalculator* calc, int num){pCalc = calc; iNum = num;} void CAddCmd::Execute(){pCalc->Add(iNum);} void CAddCmd::Undo(){pCalc->Sub(iNum);} //具體的減法命令 CSubCmd::CSubCmd(CCalculator* calc, int num){pCalc = calc; iNum = num;} void CSubCmd::Execute(){pCalc->Sub(iNum);} void CSubCmd::Undo(){pCalc->Add(iNum);} //*****************************Invoker************************************ //計算器類,計算器上有加法按鈕和減法按鈕 CController::CController(CCalcCmd* addcmd, CCalcCmd* subcmd){ pAddCmd = addcmd; pSubCmd = subcmd; } void CController::SetAddCmd(CCalcCmd* addcmd){pAddCmd = addcmd;} void CController::SetSubCmd(CCalcCmd* subcmd){pSubCmd = subcmd;} //提供給客戶使用,執行加法, 減法功能, 把操作記錄到歷史記錄裡面 void CController::Add(){ pAddCmd->Execute(); lstUndo.push_back(pAddCmd);} void CController::Sub(){ pSubCmd->Execute(); lstUndo.push_back(pSubCmd);} void CController::Undo(){ if(lstUndo.size() < 1) return; //取出最後一個命令來撤銷, 然後把最後一個命令刪除掉 CCalcCmd* pCmd = lstUndo.back(); lstUndo.pop_back(); //如果還有恢復功能,那就把這個命令記錄到恢復歷史列表中 pCmd->Undo(); lstRedo.push_back(pCmd); cout << "lstUndo.size() = " << lstUndo.size() << ", lstRedo.size() = " << lstRedo.size() << endl; } void CController::Redo(){ if(lstRedo.size() < 1) return; //取出最後一個命令來重做, 然後把最後一個命令刪除掉 CCalcCmd* pCmd = lstRedo.back(); lstRedo.pop_back(); //把這個命令記錄到可撤銷的歷史記錄裡面 pCmd->Execute(); lstUndo.push_back(pCmd); cout << "lstUndo.size() = " << lstUndo.size() << ", lstRedo.size() = " << lstRedo.size() << endl; }
//測試客戶端
void main() { CCalculator oCalculator; oCalculator.SetResult(0);//建立接收者 CAddCmd oAdd5(&oCalculator, 5);//建立命令物件,並組裝命令和接收者 CSubCmd oSub3(&oCalculator, 3); CAddCmd oAdd10(&oCalculator, 10); CSubCmd oSub4(&oCalculator, 4); CController oController(&oAdd5, &oSub3);//把命令設定到持有者 oController.Add();// 模擬按下按鈕,測試一下 cout << "一次加法運算後的結果為:" << oCalculator.GetResult() << endl; oController.Sub(); cout << "一次減法運算後的結果為:" << oCalculator.GetResult() << endl; oController.SetAddCmd(&oAdd10); oController.Add(); cout << "一次加法運算後的結果為:" << oCalculator.GetResult() << endl; //測試撤銷 oController.Undo(); cout << "撤銷一次後的結果為:" << oCalculator.GetResult() << endl; oController.Undo(); cout << "再次撤銷一次後的結果為:" << oCalculator.GetResult() << endl; //測試恢復 oController.Redo(); cout << "恢復操作一次後的結果為:" << oCalculator.GetResult() << endl; oController.Redo(); cout << "再次恢復操作一次後的結果為:" << oCalculator.GetResult() << endl; }