命令者模式

来源:互联网 发布:墙纸软件下载 编辑:程序博客网 时间:2024/05/21 23:33

命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。支持可撤销的操作。

                     把方法调用封装起来


1.  餐厅是怎么工作的

订单:用来请求餐点的对象,可以被传递;接口只有orderUp方法,封装了的准备餐点所需的动作;订单内有个需要准备工作的对象(厨师)的引用

女招待员只接受订单,然后调用订单的orderUp()方法

快餐厨师具备准备餐点的知识,女招待和厨师间彻底的解耦,不需要进行沟通

1. 客户创建一个命令对象

2. 客户利用setCommand()将命令对象存储在调用者中

3. 稍后。。。客户要求调用者执行命令。

    一旦命令被加载到调用者,该命令可以被使用并丢弃,或者可以被保留下来并使用多次


2. 家电自动化,遥控器API


public class RemoteControlTest {
    public static void main(String[] args) {
        //遥控着就是调用者
        //会传入一个命令对象,用来发出请求
        SimpleRemoteControl remote = new SimpleRemoteControl();
        //电灯对象,请求的接受者
        Light light = new Light();
        //创建一个命令,将接受者传给它
        LightOnCommand lightOn = new LightOnCommand(light);
        //命令传递给调用者
        remote.setCommand(lightOn);
        remote.buttonWasPressed();
    }
}

当有多个插槽的时候,每个插槽都具有“开”和“关”按钮。遥控器如何分辨 客厅或厨房 的电灯呢?

遥控器无法识别,创建命令并将其加载到遥控器时,我们创建的命令是两个LightCommand,一个绑定到客厅电灯对象,一个绑定到厨房的电灯对象。

命令中封装了请求的接受者,所以不要理会哪个电灯,只要exectute()被调用。

public class RemoteLoader {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        ComplexRemoteControl crc = new ComplexRemoteControl();
        
        Light livingRoomLight = new Light("Living Room");
        Light kitchenRoomLight = new Light("Kitchen Room");
        
        LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
        LightOnCommand kitchenRoomLightOn = new LightOnCommand(kitchenRoomLight);
        LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
        LightOffCommand kitchenRoomLightOff = new LightOffCommand(kitchenRoomLight);
        
        crc.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        crc.setCommand(1, kitchenRoomLightOn, kitchenRoomLightOff);
        
        System.out.println(crc.toString());
        
        crc.onButtonWasPushed(0);
        crc.onButtonWasPushed(1);
        crc.offButtonWasPushed(0);
        crc.offButtonWasPushed(1);

    }

}

主要设计目标:

让遥控器代码尽可能简单;

新的厂商类一旦出现,遥控器并不需要随之修改,从逻辑上将遥控器的类和厂商的类解耦;

降低遥控器的生产成本,大大减少未来维护时所需费用

[1] 厂商类被用来控制特定家电自动化装置 Light

[2] Command接口,每个动作都被是现成一个简单的命令对象,持有对一个厂商类的实例的引用

[3] ReomteControl管理一组命令对象,每个按钮都有一个命令对象

[4] RemoteLoader创建许多命令对象,然后加载到遥控器的插槽中


3.  取消操作

    undo

4. 使用状态实现撤销

    电风扇允许有多种转动速度

public class CeilingFanHighCommand implements Command {

    CeilingFan ceilingFan;
    int preSpeed;
    
    public CeilingFanHighCommand(CeilingFan ceilingFan){
        this.ceilingFan = ceilingFan;
    }
    public void execute() {
        preSpeed = ceilingFan.getSpeed();
        ceilingFan.high();
    }

    public void undo() {
        if(preSpeed == CeilingFan.HIGH){
            ceilingFan.high();
        }else if(preSpeed == CeilingFan.MEDIUM){
            ceilingFan.medium();
        }else if(preSpeed == CeilingFan.LOW){
            ceilingFan.low();
        }else if(preSpeed == CeilingFan.OFF){
            ceilingFan.off();
        }

    }

}


5。  拥有一个遥控器,需要光凭按下一个按钮,同时能打开和关闭电视

        使用宏命令

public class MacroCommand implements Command {

    Command[] commands;
    
    public MacroCommand(Command[] commands){
        this.commands = commands;
    }
    public void execute() {
        for(Command c : commands){
            c.execute();
        }
    }

    public void undo() {
    }

}


Command[]  partyON = {lightOn, stereOn, tvOn, hottubOn};

MacroCommand partyOnMacro = new MacroCommand ( partyON );

remoteContol.setCommand(0, partyOnMacro , null);


6. 如何实现多层次的撤销操作 : 使用堆栈记录操作过程的每一个命令,不管什么时候按下撤销操作按钮,取最上层的命令,调用它的undo方法

命令对象不完成execute方法的细节? 调用者和接收者之间的解耦程度

7. 命令可以将运算块打包(一个接收者和一组动作,然后将它传来传去,就像是一般的对象一样)

日程安排(Schedual), 线程池,工作队列

从队列中取出一个命令,调用它的execute,等待这个调用完成,然后将此命令丢弃,再取出下一个命令……

工作队列类和进行计算的对象之间完全解耦

所有记录都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前的状态。新增 store() 和 load()

8 例子

   AudioPlayer系统,播音play,倒带rewind,停止stop功能,全都由键盘具体实施



原创粉丝点击