组合使用Memento模式与Command模式实现多级Redo和Undo

总体思路

  • 利用Memento模式,为每一个执行命令之前的对象的状态创建备份。
  • 利用Command模式,将命令的调用和操作的实现解耦。
  • 通过维护一个命令和备份相对应的数组,将命令和当前对象的备份同步保存起来。
  • 设置一个当前数组的游标,标识当前回退或重做的进度。

代码实现

#include <vector>
#include <iostream>

class DoubleNumber;

//备忘录DoubleNumberMemento只能在DoubleNumber内部创建
class DoubleNumberMemento
{
	//声明DoubleNumber为友元类
	friend class DoubleNumber;
public:
	~DoubleNumberMemento() {}

private:
	//接口都声明为private
	DoubleNumberMemento(double dblValue) : m_dblValue(dblValue) {}
	

	double GetNumber()
	{
		return m_dblValue;
	}

	//记录DoubleNumber的原始状态
	double m_dblValue;
};

//DoubleNumber类
class DoubleNumber
{
public:
	DoubleNumber(double dblValue) : m_dblValue(dblValue) {}
	~DoubleNumber() {}

        //三倍计算
	void Triple()
	{
		m_dblValue *= 3.0;
	}

        //两倍计算
	void Double()
	{
		m_dblValue *= 2.0;
	}

        //显示数据
	void ShowNumber()
	{
		std::cout << m_dblValue << std::endl;
	}

	//创建备忘录
	DoubleNumberMemento* CreateMemento()
	{
		return new DoubleNumberMemento(m_dblValue);
	}

	//从备忘录恢复
	void ReinstateMemento(DoubleNumberMemento* pMem)
	{
		m_dblValue = pMem->GetNumber();
	}

private:
	double m_dblValue;
};

//命令模式
class CalcCommand
{
public:
	typedef void(DoubleNumber::*Action)();
        
        //初始化计算命令,传入数据和计算符
	CalcCommand(DoubleNumber* pNum, Action action)
	{
		_receiver = pNum;
		_action = action;
	}

        //执行命令
	void Execute()
	{
                //先备份
		m_vecMemento.push_back( _receiver->CreateMemento());
		m_vecCmd.push_back(this);

		nCurCmd++;
		(_receiver->*_action)();
	}
        
        //撤销
	static void Undo()
	{
                //到底了
		if (nCurCmd == 0)
		{
			return ;
		}
		m_vecCmd[nCurCmd - 1]->_receiver->ReinstateMemento(m_vecMemento[nCurCmd - 1]);
		nCurCmd--;
	}

        //重做
	static void Redo()
	{
                //到顶了
		if (nCurCmd >= m_vecMemento.size())
		{
			return ;
		}

		(m_vecCmd[nCurCmd]->_receiver->*(m_vecCmd[nCurCmd]->_action))();
		nCurCmd++;
	}

        //释放内存
	static void Free()
	{
		for (int i = 0; i < m_vecCmd.size(); i++)
		{
			delete m_vecCmd[i];
			delete m_vecMemento[i];
		}
	}
private:
	DoubleNumber *_receiver;
	Action _action;

	//静态变量,记录历史命令
	static std::vector<CalcCommand*> m_vecCmd;
	//静态变量,记录备忘录
	static std::vector<DoubleNumberMemento*> m_vecMemento;
	//静态变量,命令序号游标
	static int nCurCmd;
};

std::vector<CalcCommand*> CalcCommand::m_vecCmd;
std::vector<DoubleNumberMemento*> CalcCommand::m_vecMemento;
int CalcCommand::nCurCmd = 0;

void main()
{
	DoubleNumber *object = new DoubleNumber(256.0);
	object->ShowNumber();

	CalcCommand* cmdDouble = new CalcCommand(object, &DoubleNumber::Double);
	CalcCommand* cmdTriple = new CalcCommand(object, &DoubleNumber::Triple);

	cmdDouble->Execute();
	cmdTriple->Execute();
	object->ShowNumber();

	CalcCommand::Undo();
	CalcCommand::Undo();
	object->ShowNumber();

	CalcCommand::Redo();
	CalcCommand::Redo();
	object->ShowNumber();

	CalcCommand::Free();
	delete object;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值