为方便读者,本文已添加至索引: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模式具备以下一些特色:
今天的笔记就到这里了,欢迎你们批评指正!若是以为能够的话,好文推荐一下,我会很是感谢的!