设计模式之命令模式

一、模式动机

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

二、模式定义

  命令模式(Command Pattern):将 “请求”封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。命令模式也支持撤销的操作。
  命令模式包含四个角色:抽象命令类中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作;具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中;调用者即请求的发送者,又称为请求者,它通过命令对象来执行请求;接收者执行与请求相关的操作,它具体实现对请求的业务处理。UML类图:
  
这里写图片描述

三、模式示例

  请为巴斯特家电自动化公司设计一个家电自动化遥控器的API。
  
这里写图片描述

C++代码实现

#include <iostream>
#include "windows.h"

using namespace std;

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

    ~Command()
    {
    }
};

class Light
{
public:
    void on()
    {
        cout << "light on" << endl;
    }
    void off()
    {
        cout << "light off" << endl;
    }
    Light();
    ~Light();

};

Light::Light()
{
}

Light::~Light()
{
}

class NoCommand : public Command
{
public:
    void execute()
    {
        cout << "nothing" << endl;
    }
    void undo()
    {
        cout << "nothing" << endl;
    }
    NoCommand();
    ~NoCommand();
};

NoCommand::NoCommand()
{
}

NoCommand::~NoCommand()
{
}

class LightOnCommand : public Command
{
public:
    void execute()
    {
        light_->on();
    }
    void undo()
    {
        light_->off();
    }
    LightOnCommand(Light* light);
    ~LightOnCommand();
private:
    Light* light_;

};

LightOnCommand::LightOnCommand(Light* light)
    :light_(light)
{
}

LightOnCommand::~LightOnCommand()
{
}

class LightOffCommand : public Command
{
public:
    void execute()
    {
        light_->off();
    }
    void undo()
    {
        light_->on();
    }
    LightOffCommand(Light* light);
    ~LightOffCommand();
private:
    Light* light_;

};

LightOffCommand::LightOffCommand(Light* light)
    :light_(light)
{
}

LightOffCommand::~LightOffCommand()
{
}

class RemoteControl
{
public:
    void setCommand(int slot, Command* on_command, Command* off_command)
    {
        on_command_[slot] = on_command;
        off_command_[slot] = off_command;
    }
    void onButtonWasPushed(int slot)
    {
        on_command_[slot]->execute();
    }

    void offButtonWasPushed(int slot)
    {
        off_command_[slot]->execute();
    }
    RemoteControl();
    ~RemoteControl();

private:
    Command* on_command_[7];
    Command* off_command_[7];
};

RemoteControl::RemoteControl()
{
    Command* no_command = new NoCommand;
    for (int i = 0; i < 7; i++)
    {
        on_command_[i] = no_command;
        off_command_[i] = no_command;
    }
}

RemoteControl::~RemoteControl()
{
}


int _tmain(int argc, _TCHAR* argv[])
{
    RemoteControl remote_control;
    Light* light = new Light;

    LightOnCommand* living_room_light_on = new LightOnCommand(light);
    LightOffCommand* living_room_light_off = new LightOffCommand(light);
    remote_control.setCommand(0, living_room_light_on, living_room_light_off);
    remote_control.onButtonWasPushed(0);
    remote_control.offButtonWasPushed(0);
    remote_control.onButtonWasPushed(1);
    system("pause");
    return 0;
}

运行结果

这里写图片描述

四、分析总结

  命令模式将发出请求的对象和执行请求的对象解耦。在被解耦的两个对象之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。

优点:

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

缺点:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值