您的位置:首页 > 编程语言 > C语言/C++

C++下利用Command设计模式实现undo和redo

2016-06-29 11:44 549 查看

Command.hpp:

#ifndef _COMMAND_HPP
#define _COMMAND_HPP

#include <iostream>
#include <stack>
#include <string>

class Command
{
public:
Command(){}
virtual ~Command(){}

virtual void Execute() = 0;
};

class InputCommand : public Command
{
public:

InputCommand( const std::string &input )
{
mInput = input;
}
~InputCommand()
{}

void Execute()
{
printf( "current string: %s\n", mInput.c_str() );
}

private:

std::string mInput;
};

class Commander
{
public:
Commander( Command *pCmd )
{
//最初的命令数据
mUndo.push( pCmd );
}
~Commander()
{
while( false == mUndo.empty() )
{
delete mUndo.top();
mUndo.pop();
}
while( false == mRedo.empty() )
{
delete mRedo.top();
mRedo.pop();
}
}

void ExecuteCommand( Command *pCmd )
{
pCmd->Execute();
mUndo.push( pCmd );
}

void Undo()
{
if( mUndo.size() < 2 )
{
//无法后退撤销没有数据
printf( "undo failed.\n" );
return;
}

printf( "undo:\n" );

//当前命令
auto pCmd = mUndo.top();

//保存当前命令
mRedo.push( pCmd );

//弹出
mUndo.pop();

//还原到上个命令
pCmd = mUndo.top();

pCmd->Execute();
}

void Redo()
{
if( mRedo.empty() )
{
//无法前进重做没有数据
printf( "redo failed.\n" );
return;
}

printf( "redo:\n" );

auto pCmd = mRedo.top();

pCmd->Execute();

mRedo.pop();

mUndo.push( pCmd );
}

private:
std::stack< Command* > mUndo;
std::stack< Command* > mRedo;
};

#endif


Main.cpp:

#include "Command.hpp"

//模拟输入字符串,然后对输入的字符串进行undo redo操作
//你可以打开有undo redo功能的文本编辑程序测试是否是这样
//这里记录的是完整记录,即:即便在undo 或 redo 过程中又发生数据改变
//也会记录,如果不想这样在undo 或者 redo 输入新字符串时 将redo清空即可
//即认为在历史记录中修改值被认为是最新的值,不需要再redo
int main()
{
//默认没有输入字符串可以是空,这里为了演示赋值一个特殊的字符串
Commander *p = new Commander( new InputCommand( "[empty]" ) );

//输入1234
p->ExecuteCommand( new InputCommand( "1234" ) );
//输入567
p->ExecuteCommand( new InputCommand( "567" ) );
//输入xxx
p->ExecuteCommand( new InputCommand( "xxx" ) );

//执行一次undo 撤销到 567
p->Undo();
//执行一次undo 撤销到 1234
p->Undo();

//undo后中间输入新字符串 insert 覆盖 1234
p->ExecuteCommand( new InputCommand( "insert" ) );

//执行一次undo 撤销到 1234
p->Undo();

//执行一次undo 撤销到最初情况 [empty]
p->Undo();

//执行失败已经undo 到最原始情况
p->Undo();

//执行一次redo 重做到 1234
p->Redo();
//执行一次redo 重做到 insert
p->Redo();
//执行一次redo 重做到 567
p->Redo();

//redo后中间输入新字符串 insert again 覆盖 567
p->ExecuteCommand( new InputCommand( "insert again" ) );

//执行一次undo 撤销到567
p->Undo();

//执行一次redo 重做到 insert again
p->Redo();

//执行一次redo 重做到 xxx
p->Redo();

//执行失败已经redo 到最新情况
p->Redo();
delete p;
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息