【转】设计模式学习笔记(14)-命令

命令(Command)模式是一个比较有意思的模式,如果我们要操作一个对象,我们需要指定一个对该对象的应用,然后调用该对象的某一方法,这是比较常用的方法。而命令模式则是将一个命令包装成一个对象,然后在该对象上指定一个接受者,然后把命令往系统里一扔,然后就与我无关了,至于系统该怎么调用那是系统的事。这有点类似于大炮和导弹的区别。如果我们用大炮摧毁一个目标时,我们会进行计算,瞄准目标然后击中;而导弹则不同,将目标信息输入导弹后我这边就不管了,因为导弹有了目标的充足信息,它完全可以自己找到目标。命令模式就类似于导弹的这种方式。

命令模式的好处还是解耦。发送者和接受者没有明显的耦合关系,发送者只知道接受者的名字而已而接受者则一无所知,接受者依赖系统的某一个部分调用其方法而发送者也依赖于该部分,这将依赖倒置(DI)过来从而达到了降低耦合的目的。

命令模式的结构是很简单的:

Command是所有命令的接口,里面只有一个Execute方法,ConcreteCommand是一个实现,Receiver是接受者,Invoker是调Command的类。具体流程是这样的,Client构造了一个Command对象,在里面指定了接受者即Receiver,Client将该Command对象提交给系统,然后在某个条件下系统的Invoker(可以理解为专门处理Command的类)调用该Command方法,这样Client达到了间接访问Receiver的方法。

这里有一个具体的代码实现:

class Receiver 
{
public:
    void Action() {
        cout << "An action invoked!" << endl;
    }
};

这是Receiver类,往往与具体操作绑定

class Command 
{
protected:
    Command(){}
public:
    virtual void Execute() = 0;
};

定义Command接口,只有一个Execute方法

class ConcreteCommand : public Command 
{
private:
    Receiver* _receiver;
public:
    ConcreteCommand(Receiver* receiver) : _receiver(receiver){}
    void Execute() {
        _receiver->Action();
    }
};

ConcreteCommand Command接口的具体实现

class Invoker 
{
public:
    void invoke(Command* command) {
        command->Execute();
    }
};

系统负责执行各种Command的类,它由系统创建,一般只有一个实例(单例模式)。

Invoker* invoker = new Invoker();
Command* command = new ConcreteCommand(new Receiver());
invoker->invoke(command);

主方法,定义了invoker和command

最终输出结果是

An action invoked!

由于我们这个程序比较小,所以Invoker和command放在一起了,一般情况下是不在一起的,并且Invoker是不可见的,所以这种模式符合隐式调用(Implicit Invocation)风格,而这种风格能极大地减少耦合。
我们上面的例子一个Command只执行了一个操作,而实际上我们可以定义一个MacroCommand(宏命令),它可以执行一系列操作,这样由类似于Facade模式:将一系列操作组合起来,为外界提供简单的接口。

最后来看看Command模式的适用性:

  • 你需要抽象出待执行的动作以参数化某对象以达到类似于回调(Callback)的参数化机制
  • 在不同的时刻指定、排列和执行请求
  • 支持取消操作
  • 支持修改日志
  • 支持事务操作

其实上面的Invoker在实际中往往是从命令队列中取得命令的,这样就可以对命令有所取舍。Command模式是实现取消功能的关键,每次的Command可以通过栈存储结构存储,如果要取消则可以调用以往操作的逆操作。而事务则可以通过将Command分组,这样可以达到同时执行的目的。

 

原文:http://lecoding.com/articles/232.html

posted on 2013-03-05 16:09  TheKingOfKingFish  阅读(167)  评论(0)    收藏  举报

导航