自学教程 学编程从这里开始

命令模式

《命令模式》|设计模式系列第15篇

系列:行为型模式 · 命令模式(Command Pattern)
关键词:请求封装、命令对象、调用者、接收者、撤销操作、任务队列

一、什么是命令模式

命令模式(Command Pattern):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

属于行为型设计模式。

简单理解:
把请求动作单独封装成命令对象。调用者只需要发起命令,不需要知道命令具体由谁执行、怎么执行。命令对象内部持有接收者,由接收者执行真实业务。可以把命令存入队列、日志,或者实现 undo/redo 撤销重做。
例子:遥控器,每一个按键就是一条命令。按下按键(调用者),触发命令对象,命令去控制家电(接收者)。

核心意图
将请求封装成对象,实现请求与执行方解耦;支持命令排队、日志记录、撤销重做。

适用场景

  1. 需要将请求调用者和请求接收者解耦
  2. 需要对请求做排队、延迟执行、任务调度
  3. 需要支持撤销(undo)、重做(redo)操作
  4. 需要记录请求日志,方便故障恢复
  5. 宏命令:一次性批量执行一组命令

⚠️ 缺点预警:每一个动作都要创建一个命令类,会产生大量命令子类,增加代码复杂度。

二、UML结构图

角色划分:

  1. Command(抽象命令):声明执行接口 execute(),可选增加 undo()
  2. ConcreteCommand(具体命令):实现Command,持有接收者引用,调用接收者方法
  3. Invoker(调用者):持有命令对象,触发命令执行,不关心执行细节
  4. Receiver(接收者):真正执行业务逻辑的对象
  5. Client(客户端):创建命令对象,绑定接收者,设置到调用者

三、Java 完整示例

场景:RemoteControl 遥控器,控制 Light 灯,支持 turn on / turn off。
代码全部使用英文。

1. Command 抽象命令

public interface Command {
    void execute();
    void undo();
}

2. Receiver 接收者

public class Light {
    public void turnOn() {
        System.out.println("Light is turned on");
    }

    public void turnOff() {
        System.out.println("Light is turned off");
    }
}

3. ConcreteCommand 具体命令

public class LightOnCommand implements Command {
    private Light light;

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

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

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

public class LightOffCommand implements Command {
    private Light light;

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

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

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

4. Invoker 调用者

public class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }

    public void pressUndo() {
        command.undo();
    }
}

5. Client 客户端

public class Client {
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);

        RemoteControl remote = new RemoteControl();
        remote.setCommand(lightOn);
        remote.pressButton();
        remote.pressUndo();

        remote.setCommand(lightOff);
        remote.pressButton();
        remote.pressUndo();
    }
}

运行输出:

Light is turned on
Light is turned off
Light is turned off
Light is turned on

四、优缺点总结

✅ 优点

  1. 解耦调用者与接收者,调用者不需要知道接收者细节
  2. 命令对象独立,可以排队、持久化、日志记录
  3. 方便实现 undo / redo 撤销重做
  4. 新增命令只需要新增Command子类,不修改原有代码,符合开闭原则
  5. 可以组合多个命令成为宏命令,批量执行

❌ 缺点

  1. 每一个动作都需要创建一个Command类,类数量膨胀
  2. 命令的逻辑会分散在大量命令类中,增加阅读成本

五、框架源码应用

  • JDK java.lang.Runnable 是命令模式思想
  • Spring JmsTemplate 消息发送任务
  • Quartz 定时任务 Job
  • Struts Action

六、小结

命令模式核心:把请求封装成独立命令对象,分离调用者与执行者,支持撤销、任务队列。
判断点:需要把动作抽象成对象,支持排队、日志、撤销,优先命令模式。

标签:

0 条笔记