总体思路
- 利用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;
}