命令模式实现undo/redo

#include <stack>
#include <iostream>
#include <memory>

// ----- the Command Interface -----
class ICommand {
  public:
    virtual void execute() = 0;
    virtual void undo() = 0;
    virtual void redo() = 0;
};

// ----- the MODEL -----
class Tv {
  bool mOn;
  int mChannel;

public:
  Tv() {}
  void switchOn()   { mOn = true;  }
  void switchOff()  { mOn = false; }
  
  void switchChannel(int channel) {
    mChannel = channel; 
  }
  
  bool isOn()       { return mOn;      }
  int getChannel()  { return mChannel; }
};

// ----- concrete ICommand commands -----
class TvOnCommand : public ICommand {
  Tv *mTv;

public:
  TvOnCommand(Tv &tv):mTv(&tv) {}
  void execute()    { mTv->switchOn(); }
  void undo()       { mTv->switchOff();}
  void redo()       { mTv->switchOn(); }
};

class TvOffCommand : public ICommand {
  TvOnCommand mTvOnCommand;              // reuse complementary command
public:
  TvOffCommand(Tv &tv):mTvOnCommand(tv) {}
  void execute()    { mTvOnCommand.undo(); }
  void undo()       { mTvOnCommand.execute(); }
  void redo()       { mTvOnCommand.undo(); }
};

class TvSwitchChannelCommand : public ICommand {
  Tv *mTv;
  int mOldChannel;
  int mNewChannel;

public:
  TvSwitchChannelCommand(Tv *tv, int channel) {
    mTv = tv;
    mNewChannel = channel;
  }

  void execute() {
    mOldChannel = mTv->getChannel();
    mTv->switchChannel(mNewChannel); 
  }

  void undo() { 
    mTv->switchChannel(mOldChannel);
  }

  void redo() { 
    mTv->switchChannel(mNewChannel);
  }
};

// ----- our CONTROLLER with undo/redo -----
typedef std::stack<std::shared_ptr<ICommand> > commandStack_t;

class CommandManager {
  commandStack_t mUndoStack;
  commandStack_t mRedoStack;

public:
  CommandManager() {}

  void executeCmd(std::shared_ptr<ICommand> command) {
    mRedoStack = commandStack_t(); // clear the redo stack
    command->execute();
    mUndoStack.push(command);
  }

  void undo() {
    if (mUndoStack.size() <= 0) {
        return;
    }
    mUndoStack.top()->undo();          // undo most recently executed command
    mRedoStack.push(mUndoStack.top()); // add undone command to undo stack
    mUndoStack.pop();                  // remove top entry from undo stack
  }
  
  void redo() {
    if (mRedoStack.size() <= 0) {
        return;
    }
    mRedoStack.top()->redo();          // redo most recently executed command
    mUndoStack.push(mRedoStack.top()); // add undone command to redo stack
    mRedoStack.pop();                  // remove top entry from redo stack
  }
};

int main() {
  using namespace std;

  Tv tv;
  CommandManager commandManager;

  std::shared_ptr<ICommand> c1(new TvSwitchChannelCommand(&tv, 1)); // create command for switching to channel 1
  commandManager.executeCmd(c1);
  std::cout << "switched to channel " << tv.getChannel() << std::endl;
  
  std::shared_ptr<ICommand> c2(new TvSwitchChannelCommand(&tv, 2)); // create command for switching to channel 2
  commandManager.executeCmd(c2);
  std::cout << "switched to channel: " << tv.getChannel() << std::endl;
  
  std::shared_ptr<ICommand> c3(new TvSwitchChannelCommand(&tv, 3)); // create command for switching to channel 3
  commandManager.executeCmd(c3);
  std::cout << "switched to channel: " << tv.getChannel() << std::endl;
  
  std::cout << "undoing..." << std::endl;
  commandManager.undo();
  std::cout << "current channel: " << tv.getChannel() << std::endl;
  
  std::cout << "undoing..." << std::endl;
  commandManager.undo();
  std::cout << "current channel: " << tv.getChannel() << std::endl;
  
  std::cout << "redoing..." << std::endl;
  commandManager.redo();
  std::cout << "current channel: " << tv.getChannel() << std::endl;
  
  std::cout << "redoing..." << std::endl;
  commandManager.redo();
  std::cout << "current channel: " << tv.getChannel() << std::endl;

  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值