Head First Design Patterns - 命令模式

什么是命令模式

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

为什么会有命令模式

假设要设置一个遥控器,遥控器需要控制多个设备,每个设备除了开关,可能还会有属于自己的一些特定的函数,如下图所示:

如果按照常规的设计思路,遥控器中需要包含很多if ... else判断,且每次新增设备,都需要入侵到遥控器内部代码中修改,这是一个糟糕的设计,

命令模式的特点

命令模式能把动作的请求者,从实际执行动作的对象解耦。通过在设计中引入命令对象,把一些事情(像开灯)封装成一个特定对象。

如果按下遥控器,遥控器会请求命令对象去做一些事情,遥控器并不知道实际的工作内容是什么。这就相当于把遥控器和灯解耦了。

当你需要把做出请求的对象,从知道如何执行请求的对象解耦时候,可以使用命令模式。

命令模式的类图

代码案例

  1. Command接口
java 复制代码
public interface Command {
    public void execute();

    public void undo();
}
  1. 设备类
java 复制代码
public class Light {
    private String name;
    public void on() {
        System.out.println("light on");
    }

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

    public Light(String name) {
        this.name = name;
    }
}
  1. 命令对象-关灯
java 复制代码
public class LightOffCommand implements Command{
    Light light;

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

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

    @Override
    public void undo() {
        light.on();
    }
}
  1. 命令对象-开灯
java 复制代码
public class LightOnCommand implements Command {
    Light light;

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

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

    @Override
    public void undo() {
        light.off();
    }
}
  1. 命令对象-空对象
java 复制代码
public class NoCommand implements Command{
    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}

空对象经常在设计模式中用到,可以免除对null的判断

  1. 命令的接受者-相当于遥控器类
java 复制代码
public class RemoteControllerWithUndo {
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;

    public RemoteControllerWithUndo() {
        onCommands = new Command[7];
        offCommands = new  Command[7];

        Command noCommand = new NoCommand();

        for (int i = 0; i < 7; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }

        undoCommand = noCommand;
    }

    public void setCommands(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
        undoCommand = onCommands[slot];
    }

    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
        undoCommand = offCommands[slot];
    }

    public void undoButtonWasPushed() {
        undoCommand.undo();
    }

    @Override
    public String toString() {
        StringBuffer stringBuffer = new StringBuffer();

        stringBuffer.append("\n --- Remote Control --- \n");
        for (int i = 0; i < onCommands.length; i++) {
            stringBuffer.append("[slot " + i + "] " + onCommands[i].getClass().getName()
            + " " + offCommands[i].getClass().getName() + "\n");
        }

        return stringBuffer.toString();
    }
}
  1. 命令的调用者
java 复制代码
public class RemoteLoader {
    public static void main(String[] args) {
        RemoteControllerWithUndo remoteControllerWithUndo = new RemoteControllerWithUndo();

        Light livingRoomLight = new Light("living Room");

        LightOnCommand livingOnCommand = new LightOnCommand(livingRoomLight);
        LightOffCommand lightOffCommand = new LightOffCommand(livingRoomLight);

        remoteControllerWithUndo.setCommands(0, livingOnCommand, lightOffCommand);

        remoteControllerWithUndo.onButtonWasPushed(0);
        remoteControllerWithUndo.offButtonWasPushed(0);

        System.out.println(remoteControllerWithUndo);

        remoteControllerWithUndo.undoButtonWasPushed();
    }
}
  1. 结果

命令模式的应用

请求队列、日志请求

相关推荐
Zane199415 小时前
一个 new 就能创建对象,为什么还要拆出单例、工厂、建造者、原型四种模式?
设计模式
怕浪猫1 天前
一行命令复刻爆款视频,我把 Hypit 从安装跑到了出片
人工智能·设计模式·程序员
Zane19942 天前
函数式编程里的函数,其实不是你天天写的那个函数——三大编程范式的边界在哪
设计模式
Zane19943 天前
策略模式现在该不该上?一次讲清楚过度设计和设计不足怎么找平衡
设计模式
她说..3 天前
常见设计模式-模板方法模式
java·spring·设计模式·springboot
xiaofeiyang1503 天前
第六章 · 桥接 — 三支毛笔,画出九种颜色
设计模式
Shadow(⊙o⊙)4 天前
OTOL设计模式 One Thread One Loop
服务器·网络·设计模式
sarasuki4 天前
如何让LLM 能在半夜偷偷打开网易云呢?
人工智能·设计模式·agent
小王师傅665 天前
【设计模式】装饰模式(四):框架源码实战——从 Java I/O 到 Spring 到 MyBatis
java·设计模式
执明wa5 天前
Android RecyclerView 多类型, 多种 Item
android·xml·开发语言·设计模式·android studio