欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

命令模式的应用之可撤销/恢复操作的计算器

程序员文章站 2022-03-10 17:17:56
...
深度理解命令模式

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