行为型模式--命令

1、意图

  将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

2、结构

 

 3、参与者

  Command:声明执行操作的接口;

  ConcreteCommand:将一个接收者对象绑定于一个动作;

  Client:创建一个具体命令对象并设定它的接收者;

  Invoker:要求该命令执行这个请求;

  Receiver:知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

4、适用性

  当有如下需求时,可使用命令模式:

  1)抽象出待执行的动作以参数化某对象。如过程语言中的回调函数机制,将函数先行注册,待某个条件满足时再调用。命令模式是回调机制的一个面向对象的替代品;

  2)在不同的时刻指定、排列和执行请求;

  3)支持取消操作。Command的Excute操作在实施前会先存储状态,在取消操作时通过该状态来消除操作的影响。Command必须添加UnExcute操作,以取消上一次Excute的调用效果;

  4)支持修改日志,这样当系统崩溃时,这些修改可以被重新执行一遍;

  5)用构建在原语操作上的高层操作构造一个系统。这样一种结构在支持事务的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共接口使得可以用同一种方式调用所有的事务。同时使用该模式也易于添加新事务以扩展系统;

5、代码示例

class Command
{
public:
    virtual ~Command():
    virtual void Execute()= 0; 
protected:
    Command ();
};
复制代码
// OpenCommand打开一个名字由用户指定的文档。注意OpenCommand的构造器需要一个
// Application对象作为参数。AskUser是一个提示用户输入要打开的文档名的实现例程。
class OpenCommand : public Command
{
public:
    OpenCommand(Application); 
    virtual void Execute(); 
protected:
    virtual const char* AskUser(); 
private:
    Application* _application; 
    char* _response;
};

OpenCommand::OpenCommand (Application* a)
{
    _application = a; 
}
void OpenCommand::Execute ()
{
    const char* name = AskUser()
    if(name != 0)
    {
        Document* document = new Document (name);
        _application->Add (document); 
        document->open();
    }
}
复制代码
复制代码
// PasteCommand需要一个Document对象作为其接收者。该接收者将作为一个参数给PasteCommand的构造器。
class PasteCommand : public Command
{
public:
    PasteCommand(Document*); 
    virtual void Execute(); 
private:
    Document* _document;
}; 
PasteCommand::PasteCommand (Document* doc)
{
    _document = doc; 
}
void PasteCommand::Execute ()
{
    _document->Paste();
}
复制代码
复制代码
// 对于简单的不能取消和不需参数的命令,可以用一个类模板来参数化该命令的接收者。
// 我们将为这些命令定义一个模板子类SimpleCommand。用Receiver类型参数化SimpleCommand,
// 并维护一个接收者对象和一个动作之间的绑定,而这一动作是用指向一个成员函数的指针存储的。
template <class Receiver>
class SimpleCommand : public Command 
{
public:
    typedef void (Receiver::* Action)(); 
    SimpleCommand(Receiver* r, Action a):_receiver(r),_action(a){}
    
    virtual void Execute(); 
private:
    Action _action; 
    Receiver* _receiver;
};

// 构造器存储接收者和对应实例变量中的动作。Execute操作实施接收者的这个动作。
template <class Receiver>
void simpleCommand<Receiver>::Execute ()
{
    (_receiver->*_action)();
}
// 为创建一个调用Myclass类的一个实例上的Action的Command对象,仅需如下代码:
Myclass* receiver = new Myclass; 
// ...
Command* aCommand = new simpleCommand<Myclass>(receiver,&Myclass::Action);
// ...
aCommand->Execute ();
复制代码
复制代码
// MacroCommand管理一个子命令序列,它提供了增加和删除子命令的操作。
// 这里不需要显式的接收者,因为这些子命令已经定义了它们各自的接收者。
class MacroCommand : public Command
{
public:
    MacroCommand(); 
    virtual ~MacroCommand(); 
    virtual void Add(Command*); 
    virtual void Remove(Command*); 
    virtual void Execute(); 
private:
    List<Command*>* _cmds;
};

// MacroCommand的关键是它的Execute成员函数。它遍历所有的子命令并调用其各自的Execute操作。
void MacroCommand::Execute ()
{
    ListIterator<Command*> i(_cmds); 
    for (i.First(); !i.IsDone(); i.Next())
    {
        Command *c = i.CurrentItem(); 
        c->Execute();
    }
}

// 注意,如果MacroCommand实现取消操作,那么它的子命令必须以相对于Execute的实现相反的顺序执行各子命令的取消操作。
// 最后,MacroCommand必须提供管理它的子命令的操作。MacroCommand也负责删除它的子命令。
void MacroCommand::Add (Command* c)
{
    _cmds->Append(c); 
}
void MacroCommand::Remove (Command* c)
{
    _cmds->Remove(c);
}
复制代码

6、总结

  命令模式将请求封装为对象,从而可以用不同的请求对客户进行参数化。

  命令模式支持请求排队、支持撤销操作。

posted @   流翎  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示