1.动机

  • 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
  • 命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。

2.定义

  • 命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

3.结构

clipboard.png

  • Command:声明执行操作的接口;
  • ConcreteCommand:将一个接收者对象绑定于一个动作,之后,调用接收者相应的操作,以实现Execute来完成相应的命令;
  • Client:创建一个具体命令对象,但是并没有设定它的接收者;
  • Invoker:要求该命令执行这个请求;
  • Receiver:知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接收者。

以上这些对象是按照下面的方式进行协作的:

  • Client创建一个ConcreteCommand命令对象,并指定它的Receiver对象;
  • Invoker对象存储该ConcreteCommand对象;
  • 该Invoker通过调用Command对象的Execute操作来提交一个请求。如果这个命令请求是可以撤销的,ConcreteCommand就执行Execute操作之前存储当前状态以用于取消该命令请求;
  • ConcreteCommand对象调用Receiver的一些操作以执行该请求。

4.代码分析

#include <iostream>
using namespace std;

#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }

class Receiver
{
public:
    void Action()
    {
        cout << "Receiver->Action" << endl;
    }
};  

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

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

class Invoker
{
public:
    Invoker(Command *pCommand) : m_pCommand(pCommand){}
    void Invoke()
    {
        m_pCommand->Execute();
    }
private:
    Command *m_pCommand;
};

int main()
{
    Receiver *pReceiver = new Receiver();
    Command *pCommand = new ConcreteCommand(pReceiver);
    Invoker *pInvoker = new Invoker(pCommand);
    pInvoker->Invoke();
    SAFE_DELETE(pInvoker);
    SAFE_DELETE(pCommand);
    SAFE_DELETE(pReceiver);
    return 0;
}

5.模式分析

  • 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开
  • 每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。
  • 命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递
  • 命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

6.实例

电视机遥控器

  • 电视机是请求的接收者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应电视机的不同操作。抽象命令角色由一个命令接口来扮演,有三个具体的命令类实现了抽象命令接口,这三个具体命令类分别代表三种操作:打开电视机、关闭电视机和切换频道。

7.优点

  • 降低系统的耦合度。
  • 新的命令可以很容易地加入到系统中。
  • 可以比较容易地设计一个命令队列和宏命令(组合命令)。
  • 可以方便地实现对请求的Undo和Redo。

8.缺点

  • 使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

9.适用环境

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队执行请求
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
  • 系统需要将一组操作组合在一起,即支持宏命令。

燃烧你的梦
238 声望17 粉丝

« 上一篇
职责链模式
下一篇 »
解释器模式