首先,來製作我們的訂單介面─ 對照昨天的圖,就是Command,而它必須有orderUp
這個方法讓服務生去呼叫,對應到命令模式就是execute
。
class Command
{
public:
virtual void execute()=0;
};
而每個具體的訂單裡面也需要有對應的receiver及action讓執行的時候知道要啟動哪個device去做對應的動作,現在我們就來實作其中一個開燈的command:
class LightOnCommand: public Command
{
private:
Light *m_light;
public:
LightOnCommand(Light *light):m_light(light) {};
void execute () override
{
m_light->on();
}
};
接著我們可以來試著先建立一個最簡單的遙控器─按鈕只有一顆─訂單永遠只有一種─的這種遙控器:
class SimpleRemoteControl
{
private:
Command *slot;
public:
SimpleRemoteControl(){}
void setCommand(Command *command)
{
slot = command;
}
void buttonWasPressed()
{
slot->execute();
}
};
整體流程大致如下:
class RemoteControlTest // this is client
{
public:
static void main(string[] args)
{
SimpleRemoteControl remote = new SimpleRemoteControl(); // this is invoker
Light *light = new Light(); // this is receiver
LightOnCommand *lightOn = new LightOnCommand(light); // this is command (1)
remote.setCommand(lightOn); // set command (2)
remote.buttonWasPressed(); // execute! (3)
}
};
可以試著加入更多設備與對應命令。
現在來看看命令模式的定義:
命令模式可將請求封裝成物件,讓你可以將請求、佇列或記錄等物件參數化,並支援可復原的操作。
來逐步分解這個定義─首先,"將請求封裝成物件",代表著我們把送給receiver對應的行動,封裝在一個command物件中,並且只有一個公開的方法─execute;要啟動這個command的話,就是呼叫execute()
,便會啟動receiver的動作。在command以外的物件都不知道這個command物件的receiver及動作為何,只需要知道呼叫execute()
即可。這就是參數化的案例,透過將command設置到不同按鈕位置(slot),後續就可藉由不同slot的觸發來進行execute()
。
而至於佇列、紀錄以及復原動作,會在後面介紹。
前面看了定義,現在來看看它的架構長什麼樣子。
execute()
來執行請求execute()
要求receiver執行動作action()