命令模式

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();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值