命令模式

1.定义

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

  注:命令模式把接收者组合到命令中,来实现客户端调用命令执行后的动作.因为最后都是接收者要执行动作.

2.代码实现

 这边以遥控器为例子,通过点击不同的按钮来发送不同的命令,相应的各种电器收到命令后执行不同的动作.所以我们要做的就是给遥控器按钮添加命令.

定义一个Command命令接口,这是所有命令的抽象

public interface Command {
    public void execute();
}

假设有三个命令接收者,也就是说我的遥控器要控制以下三个对象,电灯,车库,音响

public class Light {
    private String name;
    
    public Light(String name) {
        super();
        this.name = name;
    }
    public void on() {
        System.out.println("Light is on");
    }
    public void off() {
        System.out.println("Light is off");
    }
    
}
public class GarageDoor {
    public void up() {
        System.out.println("GarageDoor up");
    }
    public void down() {
        System.out.println("GarageDoor down");
    }
    public void stop() {
        System.out.println("GarageDoor stop");
    }
    public void lightOn() {
        System.out.println("GarageDoor lightOn");
    }
    public void lightOff() {
        System.out.println("GarageDoor lightOff");
    }
}
public class Stereo {
    private String name;
    
    
    public Stereo(String name) {
        super();
        this.name = name;
    }
    public void on() {
        System.out.println("Stereo on");
    }
    public void off() {
        System.out.println("Stereo off");
    }
    public void setCd() {
        System.out.println("Stereo setCd");
    }
    public void setDvd() {
        System.out.println("Stereo setDvd");
    }
    public void setRadio() {
        System.out.println("Stereo setRadio");
    }
    public void setVolume() {
        System.out.println("Stereo setVolume");
    }
    
}

因为遥控器只有开和关的按钮,所以我们针对这三个接收者做出了三组命令

打开电灯,关闭电灯

package command;

public class LightOnCommand implements Command{
    Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    @Override
    public void execute() {
        light.on();
    }

}
package command;

public class LightOffCommand implements Command{
    Light light;
    
    public LightOffCommand(Light light) {
        this.light = light;
    }
    @Override
    public void execute() {
        light.off();
    }
}

可以看到,里面定义了接收者,然后实现了Command接口并且调用接收者的方法来实现execute方法.命令模式中,命令基本上都包含这接收者一起传递给调用者.

在定义

车库开,车库关

package command;

public class GarageDoorCloseCommand implements Command{
    GarageDoor garageDoor;

    
    public GarageDoorCloseCommand(GarageDoor garageDoor) {
        super();
        this.garageDoor = garageDoor;
    }

    public void setGarageDoor(GarageDoor garageDoor) {
        this.garageDoor = garageDoor;
    }

    @Override
    public void execute() {
        garageDoor.down();
    }
}
package command;

public class GarageDoorOpenCommand implements Command{
    GarageDoor garageDoor;

    
    public GarageDoorOpenCommand(GarageDoor garageDoor) {
        super();
        this.garageDoor = garageDoor;
    }

    public void setGarageDoor(GarageDoor garageDoor) {
        this.garageDoor = garageDoor;
    }

    @Override
    public void execute() {
        garageDoor.up();
    }
    
}

定义

音响开,音响关

package command;

public class StereoOffWithCDCommand implements Command {
    private Stereo stereo;
    
    public StereoOffWithCDCommand(Stereo stereo) {
        super();
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        stereo.off();
    }

}
package command;

public class StereoOnWIthCDCommand implements Command {
    private Stereo stereo;
    
    public StereoOnWIthCDCommand(Stereo stereo) {
        super();
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        stereo.on();
        stereo.setCd();
        stereo.setVolume();
    }

}

这些命令基本上都实现了Command接口

接下来定义遥控器

package command;

public class RemoteControl {
    Command[] onCommands;
    Command[] offCommands;
    
    public RemoteControl() {
        onCommands = new Command[7];
        offCommands = new Command[7];
        
        Command noCommand = new NoCommand();
        for (int i = 0; i < onCommands.length; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }
    
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    
    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
    }
    
    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
    }
    
//    
    
    
}

因为遥控器只有开和关,所以我们分别定义Command数组,构造函数中可以自定义命令数组的大小,初始化的时候赋空值.给按钮赋命令的时候也是根据两个数组下标来赋值.

在这里可以看到,RemoteControl只关心命令Command,而并不关心具体是哪一个命令,在按下按钮的时候只需要调用Command的方法就可以执行相应的动作.

接下来是测试类

package command;

public class RemoteLoader {
    public static void main(String[] args) {
        RemoteControl remoteControl = new RemoteControl();
        
        //定义命令接收者
        Light livingRoomLight = new Light("Living Room");
        Stereo stereo = new Stereo("Living Room");
        GarageDoor garageDoor = new GarageDoor();
        
        //定义命令
        LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
        GarageDoorCloseCommand garageDoorCloseCommand = new GarageDoorCloseCommand(garageDoor);
        GarageDoorOpenCommand garageDoorOpenCommand = new GarageDoorOpenCommand(garageDoor);
        StereoOffWithCDCommand stereoOffWithCDCommand = new StereoOffWithCDCommand(stereo);
        StereoOnWIthCDCommand stereoOnWIthCDCommand = new StereoOnWIthCDCommand(stereo);
        //设置命令到remoteControl
        remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        remoteControl.setCommand(1, garageDoorOpenCommand, garageDoorCloseCommand);
        remoteControl.setCommand(2, stereoOnWIthCDCommand, stereoOffWithCDCommand);
        
        //调用
        remoteControl.offButtonWasPushed(0);
        remoteControl.onButtonWasPushed(1);
        
        
    }
}

结果为

Light is off
GarageDoor up

3.总结

命令模式最主要的就是把接收者放在了命令中,通过调用接收者的方法来实现命令的execute功能.

这里还有几个拓展功能:

3.1 撤销

之前定义的时候说有撤销,这边是写下具体的思路,代码都是简单的重复代码,这里就不写一遍了.

public interface Command {
    public void execute();
    
    public void undo();//撤销
}

只需要在Command接口中添加撤销方法,并且在子类中实现undo方法,以遥控器为例子,只需要调用接收者相反的方法即可.

然后在RemoteLoader这个类中定义一个临时变量来储存上一个变量,撤销的时候直接调用这个临时变量的undo方法即可.如果是需要多次撤销.可以用栈来储存命令,然后挨个调用undo方法即可.

3.2宏命令

我们可以直接定义一个宏命令对象

public class MacroCommand implements Command{
    private Command[] command;
    
    
    public MacroCommand(Command[] command) {
        super();
        this.command = command;
    }

    @Override
    public void execute() {
        for (int i = 0; i < command.length; i++) {
            command[i].execute();
        }
    }

}

然后通过构造函数来传入想组合的命令即可.

比如:

Command[] command = {livingRoomLightOn, livingRoomLightOff};
MacroCommand mc = new MacroCommand(command);

直接把想组合的命令定义成数组,传入即可组成一个宏命令!

队列也是命令模式,队列直接把命令一个一个取出来,直接调用即可,因为命令中已经包含了接收者.

原文地址:https://www.cnblogs.com/lishuaiqi/p/11161110.html