设计模式17-命令模式:请求的封装与回放

命令模式:把请求变成可以保存和撤销的对象

点击按钮、操作队列、撤销重做、任务调度,都要求“动作”本身能像数据一样被保存和传递。命令模式把动作对象化。

一、痛点:调用者直接绑死接收者

一个智能家居系统里,用户可能通过面板、语音、定时任务三种方式执行“开灯”“关灯”“调节温度”。如果每种入口都直接调用设备方法:

if ("light-on".equals(action)) {
    light.turnOn();
} else if ("ac-up".equals(action)) {
    ac.increaseTemperature();
}

调用者和设备实现强耦合,也没法支持撤销、排队、日志回放。

命令模式的回答:把每个动作封装成 Command 对象,调用者只向命令对象发出“执行”,不关心谁真正干活

二、实现:命令接口 → 具体命令 → 调用者 → 接收者

第一步:定义命令接口

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

第二步:定义接收者

public class Light {

    private boolean on;

    public void turnOn() {
        this.on = true;
        System.out.println("[灯] 已打开");
    }

    public void turnOff() {
        this.on = false;
        System.out.println("[灯] 已关闭");
    }
}

第三步:实现具体命令

public class LightOnCommand implements Command {

    private final 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 final Light light;

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

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

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

第四步:调用者与历史记录

import java.util.ArrayDeque;
import java.util.Deque;

public class RemoteController {

    private final Deque<Command> history = new ArrayDeque<>();

    public void press(Command command) {
        command.execute();
        history.push(command);
    }

    public void undo() {
        if (!history.isEmpty()) {
            history.pop().undo();
        }
    }
}

第五步:不同入口复用同一套命令

Light light = new Light();
RemoteController controller = new RemoteController();

controller.press(new LightOnCommand(light));
controller.press(new LightOffCommand(light));
controller.undo(); // 重新开灯

面板、语音、定时任务都只是创建同一个 LightOnCommand 的入口,设备逻辑只存在一处。

三、命令模式解决的四类问题

问题命令模式的解法
调用者与执行者耦合调用者只依赖 Command 接口
需要撤销/重做命令对象保存历史,并可执行 undo
需要延迟执行或定时执行命令对象可以被排队、持久化、定时触发
需要记录操作日志每个命令天然是日志条目

四、工程化提醒

  1. 只有动作需要被管理时才引入命令模式:普通业务方法直接调用即可,别把所有调用都包装成 Command;
  2. 命令粒度要合适:一个命令最好对应一个可撤销的业务动作,太细会类爆炸,太粗会难回滚;
  3. 与真实队列配合:生产上可将 Command 序列化到消息队列,实现任务解耦和重试。

小结

命令模式一句话:把动作封装成对象,让动作可保存、可排队、可撤销。它解耦调用者与接收者,也为复杂操作管理提供了统一入口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值