命令模式(Command)

命令模式(Command

 

命令模式(Command[Action/Transaction]

意图:将一个请求封装为一个对象,从而可用不同的请求对客户参数化。对请求排队或记录请求日志,以及支持可撤消的操作。

应用:用户操作日志、撤销恢复操作。

模式结构

心得

命令对象的抽象接口(Command)提供的两个常见操作——执行和撤销,其他的命令对象要实现这个接口。命令模式使之上是将调用对象(Invoker)与被调用对象(ImageText)之间的耦合关系解除。真正调用对象操作的是具体实现的命令对象,它把具体操作封装在execute内部,并为之实现了逆向的操作(如果可以的话)。而原先的调用者(invoker)只需要执行命令对象(Command)的executeunExecute操作即可,而并不知道它操作了什么样的具体对象。使用Command将对象间的调用耦合关系解除,同时也获得了用户操作的历史信息,把这些信息记录在一个队列内部,通过顺序访问队列重复执行unExecuteexcute操作即可完成撤销和恢复的功能。原则上撤销和执行的操作是相互抵消的,但是有时这并不能精确保证,为了解决类似问题可以使用备忘录模式精确记录对象状态。另外,在命令对象继承层次中引入组合模式可以实现宏命令的功能。

举例

为了方便理解,我们把调用者(invoker)看作GUI的控件对象,用户操作空间要改变图片的大小的时候会通过多态性质调用ResizeCommandexecute操作,而该execute会执行Imageresize操作。而用户要想撤销该操作,只需要访问命令队列,执行该对象的unExecute操作即可。具体的C++实现代码如下:

// 具体用户操作的对象
class Image
{
public:
     void resize()
    {
        cout<< " 改变图片大小 "<<endl;
    }
};
class Text
{
public:
     void changeColor()
    {
        cout<< " 改变文字颜色 "<<endl;
    }
};
// 命令
class Command
{
public:
     virtual  void execute()= 0;
     virtual  void unExecute()= 0;
     virtual ~Command(){};
};
class ResizeCommand: public Command
{
    Image img;
public:
     virtual  void execute()
    {
        img.resize();
    }
     virtual  void unExecute()
    {
        cout<< " 恢复图片大小 "<<endl;
    }
};
class ColorCommand: public Command
{
    Text txt;
public:
     virtual  void execute()
    {
        txt.changeColor();
    }
     virtual  void unExecute()
    {
        cout<< " 恢复文字颜色 "<<endl;
    }
};
// 命令队列
class CmdList
{
     static  const unsigned  int maxLen= 20;
    vector<Command*>cmds;
     int curPos; // 执行点——记录卡刚执行命令在队列的位置
public:
    CmdList()
    {
        curPos=- 1;
    }
     void storeCmd(Command*cmd)
    {
         // 从执行点往后的元素先删除
         int times=cmds.size()-curPos- 1; // 执行点后边元素个数
         while(times--)
        {
            delete cmds.back(); // 清除内存
            cmds.pop_back();
        }
         // 压入新命令
        cmds.push_back(cmd);
         if(cmds.size()>maxLen) // 超过了一个元素,删除第一个
        {
            cmds.erase(cmds.begin());
        }
        curPos=cmds.size()- 1; // 插入新的元素即刚执行过,记录位置
    }
     void unDo() // 撤销
    {
         if(curPos>= 0) // 有效位置
        {
            cmds[curPos--]->unExecute();
        }
    }
     void reDo() // 恢复
    {
         if(curPos<( int)cmds.size()- 1) // 后边有节点才能恢复
        {
            cmds[++curPos]->execute();
        }
    }
    ~CmdList()
    {
         for(vector<Command*>::iterator it=cmds.begin();it!=cmds.end();++it)
        {
            delete *it;
        }
        cmds.clear();
    }
};
// 调用者
class Invoker
{
public:
     void operation(Command*cmd)
    {
        cmd->execute();
    }
};

而用户使用该模式需要的是构造合适的命令对象,发送到调用者那里就可以了。在命令成功执行后需要将该命令对象存储到命令队列去,这里根据实际需求决定存储命令的调用位置。上述代码中顺便实现了队列的撤销和恢复操作,其关键在于维护一个执行点curPos,记录当前执行过的命令对象所在的位置,当然这些对用户是不可见的。

参考文章http://www.tracefact.net/Design-Pattern/Command.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值