为方便读者,本文已添加至索引:
在上篇Chain of Responsibility(职责链)模式笔记中,我们学习了一种行为型设计模式。今天,我们继续这一主题,来学习下Command(命令)模式。可以看到职责链模式是对处理请求的对象(职能者)进行了建模,而Command模式的最大不同之处就在于,它是对请求本身进行建模的。这一点从它的名字就可以看出。所以它又有别名叫:Action(动作)、Transaction(事物)模式。
老规矩,我们首先直观地去理解什么是命令模式。日常工作中,我们常常会接受到一些“任务”,这些任务往往伴随着具体要求,并对应着特定的执行人。比如说我们做一个项目,我负责其中一个Feature。那么之后,上头提出的关于这个Feature的任何修改的“command”,都会让我去执行,因为我拥有开发这个Feature所必需的相关信息。
实现这一模型的关键点就在于Command的抽象类,它定义了一个执行操作的接口,比如说execute()操作。具体的一个Command子类将接收者作为它的一个实例变量保存,并实现execute()操作,指定接收者行动起来。我们将在示例部分进行更深入地实例讲解,那么在此之前我们可以了解下它的基本要点:
目的分类
范围准则
主要功能
适用情况
参与部分
协作过程
UML图
让我们回顾下女巫格琳达的私人订制魔法小人偶吧(详见Composite模式笔记)。它通过某种神秘的传感器作为Input装置,接收人们下达的命令,然后执行。为了简单起见,我们今天举一个具体的“武斗人偶”的例子。这种人偶俨然一位空手格斗大师,为了灵活地展现武斗技巧,它分别有对应于手臂和腿部的驱动装置(ArmDrive & LegDrive),人们可以给它下达诸如“挥击”(Punch)、“飞踢”(FlyingKick) 等命令。为了增强人偶功能的扩展性,我们当然希望它日后可以执行更多更多的命令。Command设计模式的引入帮我们很好地解决了需求。它使得调用操作的对象与知道如何实现该操作的对象解耦。我们的例子中,人偶的传感器就是调用操作的对象,而各种驱动器则是实现具体操作的对象,Command模式使得传感器不需要知道任何驱动器的信息,这非常有助于我们日后开发更多的驱动装置。
首先来看最重要的Command类:
// … Direction definitions …
#define NONE 0
#define D_SOUTH 1
#define D_NORTH 2
#define D_WEST 3
#define D_EAST 4
// … Abstract Command class …
class Command {
public:
virtual ~Command();
virtual void execute() = ;
protected:
Command();
};
接下来是PunchCommand,它会令ArmDrive对象朝用户指定的方向来狠狠重击。注意,PunchCommand的构造器需要一个ArmDrive对象作为参数。askDirection是提示用户告诉它具体的方向。
// Punch !
class PunchCommand : public Command {
public:
PunchCommand(ArmDrive*);
virtual void execute();
protected:
virtual int askDirection();
private:
ArmDrive* _drive;
};
PunchCommand::PunchCommand(ArmDrive* a) {
_drive = a;
}
void PunchCommand::execute() {
int direction = askDirection();
if (direction) {
\_drive->punch(direction);
}
}
同理我们有KickCommand需要一个LegDrive对象作为其接收者。其中askHeight是询问用户需要踢击的高度,必要的时候它得跳起来。
// Kick !
class KickCommand : public Command {
public:
KickCommand(LegDrive*);
virtual void execute();
protected:
virtual int askHeight();
virtual int askDirection();
private:
LegDrive* _drive;
};
KickCommand::PunchCommand(LegDrive* l) {
_drive = l;
}
void KickCommand::execute() {
int direction = askDirection();
int height = askHeight();
if (direction && height > ) {
\_drive->kick(direction, height);
}
}
这样一来,我们的传感器就可以通过接收并调用命令来使得小人偶动起来了:
// … Sensor Process …
ArmDrive* arm = ArmDrive::getInstance();
LegDrive* leg = LegDrive::getInstance();
Command* aCommand = new PunchCommand(arm);
aCommand->execute(); // execute command.
delete aCommand;
aCommand = new KickCommand(leg);
aCommand->execute(); // execute command.
Command模式的好处还不仅限于此。大家一定熟悉批处理、宏等概念吧。结合Composite设计模式(请见索引),我们可以设计MacroCommand,从而批量执行一系列的命令。而对于MarcroCommand本身来说,它也无需要知道其各个子命令的具体执行者,因为它只需调用子命令即可。它具有add和remove方法来管理子命令。
// … Macro Command …
class MacroCommand : public Command {
public:
MacroCommand();
virtual ~MacroCommand();
virtual void add(Command\*);
virtual void remove(Command\*);
virtual void execute();
private:
List
};
void MacroCommand::execute() {
ListIterator
for (i.first(); !i.isDone(); i.next()) {
Command\* c = i.currentItem();
c->execute();
}
}
void MacroCommand::add (Command* c) {
_cmds->append(c);
}
void MacroCommand::remove(Command* c) {
_cmds->remove(c);
}
举例来看,我们想让小人偶打出一系列拳脚组合的“连招”:
// … Punch Punch Kick and Punch …
MacroCommand* aMCmd = new MacroCommand();
aMCmd->add(new PunchCommand(arm));
aMCmd->add(new PunchCommand(arm));
aMCmd->add(new KickCommand(leg));
aMCmd->add(new PunchCommand(arm));
aMCmd->execute();
怎么样,是不是很酷!让我们来看一下这个设计的UML图:
从以上我们可以看到,Command模式具有如下一些特点:
今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!
手机扫一扫
移动阅读更方便
你可能感兴趣的文章