DESCRIPTION:
Encapsulate a request as an object, thereby letting users parameterize clients with different requests, queue or log requests, and support undoable operations
命令模式一个可以将请求封装为一个对象,从而可以参数化客户的不同请求,队列或者日志请求,并支持撤销、重做。
将请求的发起者和执行者解耦
餐厅工作:
顾客把写好的订单交给女招待 —-> 女招待拿着订单放到柜台上,喊一声:“订单来了” —-> 厨师根据订单准备餐品。
顾客根据他的需要创建(CreateOrder) 一个订单 —-> 女招待取走 (takeOrder)订单 —-> 通知(OrderUp)厨师准备餐品 —-> 厨师根据(指令 / 订单上的内容)烹调,如制作汉堡(makeBurger)、制作奶昔(makeShake) —-> Output。
订单封装了餐品的请求:
订单是一个用来请求准备餐品的对象,可以被传递。它只有一个方法:orderUp。该方法封装了准备餐品所需的动作。订单内有一个到“需要进行准备工作的对象”(也就是厨师)的引用。所有都被封装起来。
女招待不需要知道订单内容,只需要将其放到柜台,喊一声:“订单来了”即可。
女招待接受订单,调用orderUp方法,通知厨师
女招待接下顾客的订单,将订单放到柜台,调用orderUp方法让厨师准备餐品。
不同的顾客有不同的订单,女招待取走不同的订单。所有订单都传入takeOrder中,女招待要厨师准备餐品,只要调用orderUp就可以了。
厨师准备餐品
厨师是一种对象,他知道如何准备餐品。女招待调用orderUp方法,厨师开始接手,实现需要创建餐品的所有方法。
女招待和厨师之间解耦;订单封装了点餐的细节,女招待只要调用订单的方法即可,厨师看了订单就知道该做什么;厨师和女招待之间不需要沟通。
就像是遥控器,按下按钮,只要调用被控制对象的orderUp方法,灯就亮了。遥控并不需要知道事情是如何发生,也不需要知道涉及哪些对象。
客户(clinet)创建一个命令对象。
客户利用setCommand将命令对象存储在调用者(Invoker)中。
客户要求调用者执行命令(之后,该命令可以被丢弃或者被保存并使用多次)。
class Command{
virtual void excute() = 0;
};
打开电灯的命令(对象):
class LightOnCommand : public Command{
Light * light;
public:
LightOnCommand(Light * light){ // 构造器传入客厅的电灯,
this->light = light; // 并记录在变量中.
}
void execute(){ // 调用excute()方法,电灯就会打开.
light->on();
}
};
使用命令对象(调用者):
假设有一个遥控器,它只有一个按钮,一个对应的插槽。
clas SimpleRemoteControl{
Command * slot; // 该插槽持有一个命令,控制着一个装置
public:
SimpleRemoteControl(){}
void setCommand(Command * cmd){ // 设置插槽控制的命令
slot = cmd; // 调用该方法可以改变遥控器按钮的行为
}
void buttonnWasPressed(){ // 按下按钮时,会调用该方法
slot->execute(); // 调用excute()方法
}
}
测试(客户):
Light * light = new Light();
LightOnCommand * lightOn = new LightOnCommand(light);
SimpleRemoteControl * rmt = new SimpleRemoteControl();
rmt>etCommand(lightOn);
rmt->buttonWasPressed();
命令模式
将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
命令对象只有execute()方法,它 将 动作和接收者 囊入其中。当调用execute()方法时,接收者就会执行动作。∴外面对象不知道哪个接收者做了那些动作。
遥控器中,将“开灯”命令加载进入按钮槽,然后又替换为“开门”。就像女招待一样,女招待不用管是什么订单;同理,遥控不用管是什么命令。只要该命令实现了Command接口就可以了。
当按钮按下时,就会调用相应命令的excute()方法,在方法中,相应的动作会被调用。如调用灯的开与关。
对于有开与关的两个按钮
class RemoteContrl{
Command * onCmd;
Command * offCmd;
public:
RemoteContrl(){
onCmd = new NoCommand();
offCmd= new NoCommand();
}
void setCmd(Command onCmd, Command *onCmd, Command *offCmd ){
this->onCmd = onCmd;
this->offCmd = offCmd;
}
void onBtnWasPushed(){
onCmd->excute();
}
void offBtnWasPushed(){
offCmd->excute();
}
};
空对象: 处理null
class NoCommand: public Command{
void execute(){}
};
RemoteControl *rmtCtrl = new RemoteControl();
Light *livingRoomLight = new Light();
LightOnCommand *LightOnCmd = new LightOnCommand(livingRoomLight );
LightOffCommand *LightOffCmd = new LightOffCommand(livingRoomLight );
rmtCtrl->setCmd(LightOnCmd, LightOffCmd);
rmtCtrl->onBtnWasPushed();
rmtCtrl->offBtnWasPushed();
撤销:
class Command{
virtual void execute();
virtual void undo(); // 撤销
};
打开和关闭命令
class LightOnCommand: public Command{ // LightOnCommand
Light * light;
public:
LightOnCommand(Light * light){ // LightOnCommand
this->light = light;
}
void execute(){
light->on(); // light->on();
}
void undo(){
light->off(); // light->off();
}
}
class LightOffCommand: public Command{ // LightOffCommand
Light * light;
public:
LightOffCommand(Light * light){ // LightOffCommand
this->light = light;
}
void execute(){
light->off();
}
void undo(){
light->on();
}
}
带撤销功能的遥控:
class RemoteControlWithUndo{
private:
Command *onCmd;
Command *offCmd;
Command *undoCmd;
NoCmd *noCmd
public:
RemoteControlWithUndo(){
noCmd = new NoCmd();
onCmd = noCmd; // 指向同一个对象noCmd
offCmd = noCmd; // 只存在一个noCmd实体
undoCmd = noCmd;
}
void setCommand(Command *onCmd, Command *offCmd){
this->onCmd = onCmd;
this->offCmd = offCmd;
}
void onBtnWasPushed(){
onCmd->execute();
undoCmd = onCmd; // undoCmd被赋予了当前执行的命令对象。
}
void offBtnWasPushed(){
offCmd->execute();
undoCmd = offCmd;
}
void undoBtnWasPushed(){
undoCmd->undo(); // 按下撤销按钮时,执行对应命令对象的撤销功能
}
virtual ~RemoteControlWithUndo(){delete noCmd; noCmd=NULL;}
};
其中NoCmd
class NoCmd{
public:
virtual void execute() {};
virtual void undo() {};
};
一个按钮,循环执行多个命令:
class MacroCmd : public Command{
vector<Command *> cmds;
public:
MacroCmd(const vector<Command *> &v_cs){
cmds = v_cs;
}
void execute(){
for(int i=0; i<cmds.size(); ++i){
cmds[i]->excute();
}
}
void undo(){
for(int i=0; i<cmds.size(); ++i){
cmds[i]->undo();
}
}
}