命令模式

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

现在有如下图遥控器。有3个可编程的插槽,以及对应的按钮。黑色按钮为开关按钮,有按下和弹起,两种状态。红色按钮为撤销按钮,撤销上一次操作,只有一种状态,按下立即弹起。
这里写图片描述

现在有两个电器。

// 电灯对象
public class Light {

    public void on(){
        System.out.println("light on ...");
    }

    public void off(){
        System.out.println("light off ...");
    }
}

// 音响对象
public class Stereo {

    private String name;
    private int volume;

    public void on() {
        System.out.println("stereo on ...");
    }

    public void off() {
        System.out.println("stereo off ...");
    }

    public void insertCD(String name) {
        this.name = name;
        System.out.println("CD " + name + " insert ...");
    }

    public void takeCD() {
        this.name = "";
        System.out.println("CD " + name + " take ...");
    }

    public void setVolume(int volume) {
        this.volume = volume;
        System.out.println("volume set " + volume);
    }
}

类图

这里写图片描述

我们通过编程来让遥控器控制电器。

// 命令接口
public interface Command {

    void execute();

    void undo();
}

// 空命令
public class NoCommand implements Command {
    @Override
    public void execute() {
        System.out.println("command is null");
    }

    @Override
    public void undo() {
        System.out.println("command is null");
    }
}

// 开启电灯命令
public class LightOn implements Command {

    private Light light;

    public LightOn(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }

    @Override
    public void undo() {
        light.off();
    }
}

// 电灯关闭命令
public class LightOff implements Command {

    private Light light;

    public LightOff(Light light) {
        this.light = light;
    }

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

    @Override
    public void undo() {
        light.on();
    }
}

// 打开音响命令
public class StereoOn implements Command {

    private Stereo stereo;

    public StereoOn(Stereo stereo) {
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        stereo.on();
        stereo.insertCD("XXX CD");
        stereo.setVolume(10);
    }

    @Override
    public void undo() {
        stereo.setVolume(0);
        stereo.takeCD();
        stereo.off();
    }
}

// 关闭音响命令
public class StereoOff implements Command {

    private Stereo stereo;

    public StereoOff(Stereo stereo) {
        this.stereo = stereo;
    }

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

    @Override
    public void undo() {
        stereo.on();
        stereo.insertCD("XXX CD");
        stereo.setVolume(10);
    }
}

// 宏命令
public class Macro implements Command {

    private List<Command> list;

    public Macro(List<Command> list) {
        this.list = list;
    }

    @Override
    public void execute() {
        for (Command command : list) {
            command.execute();
        }
    }

    @Override
    public void undo() {
        for (Command command : list) {
            command.undo();
        }
    }
}

// 遥控器
public class RemoteControl {

    // 遥控器上插槽的数量
    private int num = 3;

    private Command[] onCommands;
    private Command[] offCommands;
    private Stack<Command> historyCommands;

    public RemoteControl() {
        onCommands = new Command[num];
        offCommands = new Command[num];
        historyCommands = new Stack<>();
        Command noCommand = new NoCommand();  // 所有插槽初始化为同一个空对象
        for (int i = 0; i < num; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }

    public void setCommand(int slot, Command onCommand, Command offCommand) {
        if (slot < num && slot > -1) {
            onCommands[slot] = onCommand;
            offCommands[slot] = offCommand;
        } else {
            throw new ArrayIndexOutOfBoundsException("slot is not exist");
        }
    }

    // 按下按钮
    public void buttonDown(int slot) {
        if (slot < num && slot > -1) {
            onCommands[slot].execute();
            historyCommands.push(onCommands[slot]);
        } else {
            throw new ArrayIndexOutOfBoundsException("slot is not exist");
        }
    }

    // 按钮弹起
    public void buttonUp(int slot) {
        if (slot < num && slot > -1) {
            offCommands[slot].execute();
            historyCommands.push(offCommands[slot]);
        } else {
            throw new ArrayIndexOutOfBoundsException("slot is not exist");
        }
    }

    // 撤销按钮
    public void undo() {
        if (historyCommands.isEmpty()) {
            System.out.println("do not have history command");
        } else {
            historyCommands.pop().undo();
        }
    }
}

// 测试类
public class Test {

    public static void main(String[] args) {
        new Test().test();
    }

    private void test() {
        // 遥控器对象
        RemoteControl remoteControl = new RemoteControl();

        // 各种家电
        Light light = new Light();
        Stereo stereo = new Stereo();

        // 命令
        LightOn lightOn = new LightOn(light);
        LightOff lightOff = new LightOff(light);
        StereoOn stereoOn = new StereoOn(stereo);
        StereoOff stereoOff = new StereoOff(stereo);

        // 宏命令
        List<Command> onCommands = new ArrayList() {
            {
                add(lightOn);
                add(stereoOn);
            }
        };
        Macro macroOn = new Macro(onCommands);
        List<Command> offCommands = new ArrayList() {
            {
                add(lightOff);
                add(stereoOff);
            }
        };
        Macro macroOff = new Macro(offCommands);

        // 插入命令
        remoteControl.setCommand(0, lightOn, lightOff);
        remoteControl.setCommand(1, stereoOn, stereoOff);
        remoteControl.setCommand(2, macroOn, macroOff);

        // 操作遥控器
        remoteControl.buttonDown(0);
        remoteControl.buttonUp(0);
        remoteControl.buttonDown(1);
        remoteControl.buttonUp(1);
        remoteControl.buttonDown(2);
        remoteControl.buttonUp(2);
        System.out.println(11111);
        remoteControl.undo();
        remoteControl.undo();
        remoteControl.undo();

    }
}

注:

  • 我们把所有的电器的操作封装,暴露execute和undo方法。现在遥控器可以很方便的统一操作各种电器。
  • 将发出请求的对象和接受请求的对象解耦
  • 可以用来实现队列、日志、事务等
  • 队列:一个线程负责把命令封装放入对序列中,另一个线程从队列中取出命令,调用execute方法
  • 日志:把每次的操作记录下来,出现异常时读取日志,重新执行被记录的操作

参考文章
1. Head First 设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值