組合使用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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章