設計模式之 《命令模式》

介紹

  • 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]
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章