總體思路
- 利用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;
}