命令模式(Command Pattern)

命令模式:將請求封裝成物件,可以讓我們使用不同的請求、佇列、或者日誌來參數化其他物件。

我們用遙控器來解釋命令模式,假使要設計操作家電的遙控器,按鍵代表操作某個家電,我們不將操作細節寫在搖控器物件上,而是將命令和按鍵綁定,當我們按下按鍵時,透過之前綁定的命令,遙控器知道要將訊息通知哪個物件,由此物件進行實際的操作。

實作上我們定義Command命令類別,命令實例皆繼承於此類別,命令實例透過傳入參數得到接收者,execute()方法定義實際的操作,用RemoteControl類別的setCommand()方法,將某個命令和遙控器相關,Light和Door是接收命令的接收者,並進行實際的操作,以下為程式碼。

#include <iostream>
using namespace std;

class Light{
public:
    void on(){cout<<"開燈"<on();}
};
class DoorOpenCommand : public Command{
private:
    Door *m_door;
public:
    DoorOpenCommand(Door *door){m_door=door;}
    void execute(){m_door->open();}
};

class RemoteControl{
private:
    Command *slot;
public:
    void setCommand(Command *command){slot=command;}
    void pressButton(){slot->execute();}
};

int main(){
    RemoteControl myControl;
    Light myLight;
    Door myDoor;
    Light OnCommandcommand1(&myLight);
    Door OpenCommandcommand2(&myDoor);

    myControl.setCommand(&command1);
    myControl.pressButton();
    myControl.setCommand(&command2);
    myControl.pressButton();
    return 0;
}

下面實作有多個按鍵的遙控器,可以存放3個開與關的命令,我們使用陣列記錄這些命令,以下為程式碼。

#include <iostream>
using namespace std;

class Light{
public:
    void on(){ cout << "開燈" << endl; }
    void off(){ cout << "關燈" << endl; }
};
class Door{
public:
    void open(){ cout << "開門" << endl; }
    void close(){ cout << "關門" << endl; }
};

class Command{
public:
    virtual void execute() = 0;
};
class NoCommand: public Command{
public:
    void execute(){ cout << "尚未綁定命令" << endl; }
};
class LightOnCommand: public Command{
private:
    Light *m_light;
public:
    LightOnCommand(Light *light){ m_light = light; }
    void execute(){ m_light->on(); }
};
class LightOffCommand: public Command{
private:
    Light *m_light;
public:
    LightOffCommand(Light *light){ m_light = light; }
    void execute(){ m_light->off(); }
};
class DoorOpenCommand: public Command{
private:
    Door *m_door;
public:
    DoorOpenCommand(Door *door){ m_door = door; }
    void execute(){ m_door->open(); }
};
class DoorCloseCommand: public Command{
private:
    Door *m_door;
public:
    DoorCloseCommand(Door *door){ m_door = door; }
    void execute(){ m_door->close(); }
};

class RemoteControl{
private:
    Command *m_onCommands[3];
    Command *m_offCommands[3];
public:
    RemoteControl(Command *);
    void setCommand(int slot, Command *on, Command *off);
    void pressOnButton(int slot){ m_onCommands[slot]->execute(); }
    void pressOffButton(int slot){ m_offCommands[slot]->execute(); }
};
RemoteControl::RemoteControl(Command *command){
    for (int i = 0; i < 3; i++){
        m_onCommands[i] = command;
        m_offCommands[i] = command;
    }
}
void RemoteControl::setCommand(int slot, Command *on, Command *off){
    m_onCommands[slot] = on;
    m_offCommands[slot] = off;
}

int main(){
    Light myLight;
    Door myDoor;
    LightOnCommand command1(&myLight);
    LightOffCommand command2(&myLight);
    DoorOpenCommand command3(&myDoor);
    DoorCloseCommand command4(&myDoor);

    NoCommand nocommand;
    RemoteControl myControl(&nocommand);
    myControl.setCommand(0, &command1, &command2);
    myControl.setCommand(1, &command3, &command4);
    for (int i = 0; i < 3; i++){
        myControl.pressOnButton(i);
        myControl.pressOffButton(i);
    }
    system("PAUSE");
    return 0;
}