1. 程式人生 > >命令模式的應用之可撤銷/恢復操作的計算器

命令模式的應用之可撤銷/恢復操作的計算器

深度理解命令模式

(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;
}