爲方便讀者,本文已添加至索引:html
在上篇Chain of Responsibility(職責鏈)模式筆記中,咱們學習了一種行爲型設計模式。今天,咱們繼續這一主題,來學習下Command(命令)模式。能夠看到職責鏈模式是對處理請求的對象(職能者)進行了建模,而Command模式的最大不一樣之處就在於,它是對請求自己進行建模的。這一點從它的名字就能夠看出。因此它又有別名叫:Action(動做)、Transaction(事物)模式。設計模式
老規矩,咱們首先直觀地去理解什麼是命令模式。平常工做中,咱們經常會接受到一些「任務」,這些任務每每伴隨着具體要求,並對應着特定的執行人。好比說咱們作一個項目,我負責其中一個Feature。那麼以後,上頭提出的關於這個Feature的任何修改的「command」,都會讓我去執行,由於我擁有開發這個Feature所必需的相關信息。app
實現這一模型的關鍵點就在於Command的抽象類,它定義了一個執行操做的接口,好比說execute()操做。具體的一個Command子類將接收者做爲它的一個實例變量保存,並實現execute()操做,指定接收者行動起來。咱們將在示例部分進行更深刻地實例講解,那麼在此以前咱們能夠了解下它的基本要點:學習
讓咱們回顧下女巫格琳達的私人訂製魔法小人偶吧(詳見Composite模式筆記)。它經過某種神祕的傳感器做爲Input裝置,接收人們下達的命令,而後執行。爲了簡單起見,咱們今天舉一個具體的「武鬥人偶」的例子。這種人偶儼然一位空手格鬥大師,爲了靈活地展示武鬥技巧,它分別有對應於手臂和腿部的驅動裝置(ArmDrive & LegDrive),人們能夠給它下達諸如「揮擊」(Punch)、「飛踢」(FlyingKick) 等命令。爲了加強人偶功能的擴展性,咱們固然但願它往後能夠執行更多更多的命令。Command設計模式的引入幫咱們很好地解決了需求。它使得調用操做的對象與知道如何實現該操做的對象解耦。咱們的例子中,人偶的傳感器就是調用操做的對象,而各類驅動器則是實現具體操做的對象,Command模式使得傳感器不須要知道任何驅動器的信息,這很是有助於咱們往後開發更多的驅動裝置。spa
首先來看最重要的Command類:設計
1 // ... Direction definitions ... 2 #define NONE 0 3 #define D_SOUTH 1 4 #define D_NORTH 2 5 #define D_WEST 3 6 #define D_EAST 4 7 8 // ... Abstract Command class ... 9 class Command { 10 public: 11 virtual ~Command(); 12 virtual void execute() = 0; 13 protected: 14 Command(); 15 };
接下來是PunchCommand,它會令ArmDrive對象朝用戶指定的方向來狠狠重擊。注意,PunchCommand的構造器須要一個ArmDrive對象做爲參數。askDirection是提示用戶告訴它具體的方向。日誌
1 // Punch ! 2 class PunchCommand : public Command { 3 public: 4 PunchCommand(ArmDrive*); 5 6 virtual void execute(); 7 protected: 8 virtual int askDirection(); 9 private: 10 ArmDrive* _drive; 11 }; 12 13 PunchCommand::PunchCommand(ArmDrive* a) { 14 _drive = a; 15 } 16 17 void PunchCommand::execute() { 18 int direction = askDirection(); 19 20 if (direction) { 21 _drive->punch(direction); 22 } 23 }
同理咱們有KickCommand須要一個LegDrive對象做爲其接收者。其中askHeight是詢問用戶須要踢擊的高度,必要的時候它得跳起來。code
1 // Kick ! 2 class KickCommand : public Command { 3 public: 4 KickCommand(LegDrive*); 5 6 virtual void execute(); 7 protected: 8 virtual int askHeight(); 9 virtual int askDirection(); 10 private: 11 LegDrive* _drive; 12 }; 13 14 KickCommand::PunchCommand(LegDrive* l) { 15 _drive = l; 16 } 17 18 void KickCommand::execute() { 19 int direction = askDirection(); 20 int height = askHeight(); 21 22 if (direction && height > 0) { 23 _drive->kick(direction, height); 24 } 25 }
這樣一來,咱們的傳感器就能夠經過接收並調用命令來使得小人偶動起來了:htm
1 // ... Sensor Process ... 2 ArmDrive* arm = ArmDrive::getInstance(); 3 LegDrive* leg = LegDrive::getInstance(); 4 Command* aCommand = new PunchCommand(arm); 5 aCommand->execute(); // execute command. 6 delete aCommand; 7 aCommand = new KickCommand(leg); 8 aCommand->execute(); // execute command.
Command模式的好處還不只限於此。你們必定熟悉批處理、宏等概念吧。結合Composite設計模式(請見索引),咱們能夠設計MacroCommand,從而批量執行一系列的命令。而對於MarcroCommand自己來講,它也無須要知道其各個子命令的具體執行者,由於它只需調用子命令便可。它具備add和remove方法來管理子命令。對象
1 // ... Macro Command ... 2 class MacroCommand : public Command { 3 public: 4 MacroCommand(); 5 virtual ~MacroCommand(); 6 7 virtual void add(Command*); 8 virtual void remove(Command*); 9 10 virtual void execute(); 11 private: 12 List<Command*>* _cmds; 13 }; 14 15 void MacroCommand::execute() { 16 ListIterator<Command*> i (_cmds); 17 18 for (i.first(); !i.isDone(); i.next()) { 19 Command* c = i.currentItem(); 20 c->execute(); 21 } 22 } 23 24 void MacroCommand::add (Command* c) { 25 _cmds->append(c); 26 } 27 28 void MacroCommand::remove(Command* c) { 29 _cmds->remove(c); 30 }
舉例來看,咱們想讓小人偶打出一系列拳腳組合的「連招」:
1 // ... Punch Punch Kick and Punch ... 2 MacroCommand* aMCmd = new MacroCommand(); 3 aMCmd->add(new PunchCommand(arm)); 4 aMCmd->add(new PunchCommand(arm)); 5 aMCmd->add(new KickCommand(leg)); 6 aMCmd->add(new PunchCommand(arm)); 7 aMCmd->execute();
怎麼樣,是否是很酷!讓咱們來看一下這個設計的UML圖:
從以上咱們能夠看到,Command模式具備以下一些特色:
今天的筆記就到這裏了,歡迎你們批評指正!若是以爲能夠的話,好文推薦一下,我會很是感謝的!