设计模式之 《命令模式》

介绍

  • Receive接收者角色
    该角色就是干活的角色, 命令传递到这里是应该被执行的。作为抽象类,定义一个可接受消息的抽象类,从而保证多个不同的具体角色均可接受命令
  • Command命令角色
    需要执行的所有命令都在这里声明。定义抽象类一个和一系列具体命令类,每个类对应一个命令。
  • Invoker调用者角色
    接收到命令, 并执行命令。

优点:类间解耦、可扩展性 、命令模式结合其他模式会更优秀

缺点: 如果有N个命令, Command的子类就是N个

UML类图:

简单示例:

#ifndef SIMPLE_COMMAND_H
#define SIMPLE_COMMAND_H

#include <iostream>
using namespace std;

/**
 * @brief The Receiver class
 * Receiver类,知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者。
 */
class Receiver
{
public:
    void action()
    {
        cout<<"执行请求!"<<endl;
    }
};


/**
 * @brief The Command class
 * Command类,用来声明执行操作的接口。
 */
class Command
{

public:
    Command(Receiver * receiver)
    {
        m_receiver = receiver;
    }

    virtual void execute() = 0;
protected:
    Receiver *m_receiver;
};


/**
 * @brief The ConcreteCommand class
 * ConcreteCommand类,将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute。
 */
class ConcreteCommand : public Command
{
public:
    ConcreteCommand(Receiver *receiver)
        :Command(receiver)
    {

    }

    void execute() override
    {
        cout<<"ConcreteCommand:\n";
        m_receiver->action();
    }
};


/**
 * @brief The Invoker class
 * Invoker类,要求该命令执行这个请求。
 */
class Invoker
{
public:
    void setCommand(Command *command)
    {
        m_command = command;
    }

    void executeCommand()
    {
        m_command->execute();
    }
private:
    Command *m_command;
};


#endif // SIMPLE_COMMAND_H

大话设计模式第23章烧烤摊:(最近地摊经济挺火的)

UML类图:

代码:

#ifndef BARBECUE_COMMAND_H
#define BARBECUE_COMMAND_H


#include <iostream>
#include <list>
#include <ctime>
using namespace std;


/**
 * @brief The Barbecuer class
 * 烤肉师
 */
class Barbecuer
{
public:
    void BakeMutton()
    {
        cout<<"烤羊肉串!"<<endl;
    }

    void BakeChickenWing()
    {
        cout<<"烤鸡翅!"<<endl;
    }
};

/**
 * @brief The Command class
 * 抽象命令类
 */
class Command
{
public:
    Command(Barbecuer *receiver)
    {
        m_receiver = receiver;
    }

    void setCmd(string strCmd)
    {
        m_strCmd = strCmd;
    }

    string getCmdString() const
    {
        return m_strCmd;
    }


    virtual void excuteCommand() = 0;
protected:
    Barbecuer *m_receiver;
    string m_strCmd;
};

/**
 * @brief The BakeMuttonCommand class
 * 烤肉命令
 */
class BakeMuttonCommand : public Command
{
public:
    BakeMuttonCommand(Barbecuer *receiver)
        :Command(receiver)
    {
        m_strCmd = "烤羊肉串";
    }

    void excuteCommand() override
    {
        m_receiver->BakeMutton();
    }
};
/**
 * @brief The BakeChickenWingCommand class
 * 烤鸡翅命令
 */
class BakeChickenWingCommand : public Command
{
public:
    BakeChickenWingCommand(Barbecuer *receiver)
        :Command(receiver)
    {
        m_strCmd = "烤鸡翅";
    }

    void excuteCommand() override
    {
        m_receiver->BakeChickenWing();
    }
};

/**
 * @brief The Waiter class
 * 服务员
 */
class Waiter
{
public:
    Waiter()
    {
        m_list.clear();
    }
    void setOrder(Command *cmd)
    {

        m_list.push_back(cmd);
        // 基于当前系统的当前日期/时间
        time_t now = time(0);
        // 把 now 转换为字符串形式
        char* dt = ctime(&now);
        cout<<"增加订单:"<<cmd->getCmdString()<<"时间:"<< dt << endl;
    }

    void cancelOrder(Command *cmd)
    {
        m_list.remove(cmd);
        // 基于当前系统的当前日期/时间
        time_t now = time(0);
        // 把 now 转换为字符串形式
        char* dt = ctime(&now);
        cout<<"取消订单:"<<cmd->getCmdString()<<"时间:"<< dt << endl;
    }

    void notify()
    {
        for (list<Command*>::iterator it = m_list.begin(); it != m_list.end(); it++) {
            (*it)->excuteCommand();
        }

    }
private:
    list<Command*> m_list;
};


#endif // BARBECUE_COMMAND_H

总结:(来自大话设计模式)

第一,它能较容易地设计一一个命令队列;

第二,在需要的情况下,可以较容易地将命令记入日志;

第三,允许接收请求的一方决定是否要否决请求。”

第四,可以容易地实现对请求的撤销和重做;

第五,由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。其实还有最关键的优点就是命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。[DP]
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liu-Eleven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值