设计模式-命令模式

发布于:2025-05-11 ⋅ 阅读:(213) ⋅ 点赞:(0)

写在前面

Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!

一、什么是命令模式?

命令模式是行为模式中的一种,通过将请求封装成对象,使开发者可以用不同的请求、队列或日志来参数化其他对象。
类比订外卖的过程:用户(触发者)在APP下单(命令),餐厅收到订单后(接收者)开始制作。平台不需要关心具体由谁做饭,只负责传递订单。

二、命令模式解释

命令模式的核心架构:

  1. 命令(Command)
    声明执行操作的统一接口,将请求封装为独立对象,使调用者与实现者解耦。

  2. 接收者(Receiver)
    封装具体业务能力,仅关注领域逻辑实现,不感知调用流程。

  3. 具体命令(ConcreteCommand)
    持有 Receiver 引用,在 Command 接口方法中通过委托执行 Receiver 的业务方法,可存储请求上下文参数。

  4. 触发者(Invoker)
    维护命令执行入口(触发命令方法),支持命令的存储和调度(如实现命令队列或历史记录),仅依赖 Command 接口。

  5. 客户端(Client)
    创建 Receiver 实例,构造 ConcreteCommand 并绑定 Receiver,配置 Invoker 与命令的关联关系。

三、案例实践

以居家控制系统为例,实现对灯光、空调的远程控制。先展示不使用命令模式的实现,再分析其不足。

基础类(接收者)

// 电灯类
public class Light {
    public void on() { System.out.println("开灯"); }
    public void off() { System.out.println("关灯"); }
}

// 空调类
public class AirConditioner {
    public void on() { System.out.println("空调开启"); }
    public void off() { System.out.println("空调关闭"); }
}

硬编码实现

public class HomeController {
    private Light light;
    private AirConditioner ac;

    public HomeController() {
        light = new Light();
        ac = new AirConditioner();
    }

    // 每新增一个设备,就需要修改 switch-case
    public void executeCommand(String command) {
        switch (command) {
            case "LIGHT_ON": light.on(); break;
            case "AC_ON": ac.on(); break;
            default: System.out.println("未知命令");
        }
    }
}

问题分析:新增设备(如窗帘)时,必须修改 HomeController 的 switch-case 结构。随着功能增加,代码将难以维护,且难以实现组合操作。

命令模式实现

1. 抽象命令类
public interface Command {
    void execute();  // 执行命令(例如开灯)
    void undo();     // 撤销命令(例如关灯)
}
2. 具体命令
// 电灯命令
public class LightOnCommand implements Command {
    private Light light;
    public LightOnCommand(Light light) { this.light = light; }
    @Override
    public void execute() { light.on(); }
    @Override
    public void undo() { light.off(); }
}

// 空调命令
public class ACOnCommand implements Command {
    private AirConditioner ac;
    public ACOnCommand(AirConditioner ac) { this.ac = ac; }
    @Override
    public void execute() { ac.on(); }
    @Override
    public void undo() { ac.off(); }
}
3. 控制器(触发者)
public class SmartHomeController {
    // 命令存储
    private Map<String, Command> commands = new HashMap<>();
    // 操作历史记录
    private Stack<Command> history = new Stack<>();

    // 绑定命令:例如将"开灯"按钮绑定到 LightOnCommand
    public void setCommand(String buttonName, Command command) {
        commands.put(buttonName, command);
    }

    // 执行命令
    public void executeCommand(String buttonName) {
        Command cmd = commands.get(buttonName);
        if (cmd != null) {
            cmd.execute();
            history.push(cmd); // 记录历史操作
        }
    }

    // 撤销上一步
    public void undoLastCommand() {
        if (!history.isEmpty()) {
            Command lastCmd = history.pop();
            lastCmd.undo();
        }
    }
}
4. 测试类(客户端)
@Test
public void test() {
    Light light = new Light();
    AirConditioner ac = new AirConditioner();
    SmartHomeController controller = new SmartHomeController();

    // 绑定命令
    controller.setCommand("开灯", new LightOnCommand(light));
    controller.setCommand("开空调", new ACOnCommand(ac));

    // 执行操作
    controller.executeCommand("开灯");    // 输出:开灯
    controller.executeCommand("开空调");  // 输出:空调开启
    controller.undoLastCommand();        // 输出:空调关闭
}

四、如何新增设备?以窗帘为例

1. 新增窗帘类(接收者)
public class Curtain {
    public void open() { System.out.println("打开窗帘"); }
    public void close() { System.out.println("关闭窗帘"); }
}
2. 新增窗帘命令
public class CurtainCommand implements Command {
    private Curtain curtain;
    public CurtainCommand(Curtain curtain) { this.curtain = curtain; }
    @Override
    public void execute() { curtain.close(); } // 执行:关闭窗帘
    @Override
    public void undo() { curtain.open(); }     // 撤销:打开窗帘
}
3. 使用新功能(无需修改控制器)
// 绑定新命令
Curtain curtain = new Curtain();
controller.setCommand("关窗帘", new CurtainCommand(curtain));
controller.executeCommand("关窗帘");  // 输出:关闭窗帘

改进效果:新增设备时,只需添加对应的 Command 类,无需修改控制器代码,且更容易实现组合命令。

五、长话短说

核心思想

将操作抽象为独立对象,通过参数化方式传递请求,解耦调用者与实现者。

适用场景

  • 需要解耦请求发送者与执行者

  • 需支持撤销/重做操作

  • 需实现事务操作(组合命令)

  • 需记录操作历史

  • 需支持任务队列或线程池调度

代码实现步骤

  1. 定义 Command 接口,声明执行方法。

  2. 创建具体命令类实现接口,并注入 Receiver 对象。

  3. 创建 Invoker 类管理命令对象。

  4. 客户端初始化顺序:
    a. 创建 Receiver
    b. 创建 Command 并关联 Receiver
    c. 创建 Invoker 并绑定 Command

  5. 通过 Invoker 执行命令。

典型应用

  • 智能家居控制系统

  • 文本编辑器的撤销/重做

  • 事务型数据库操作

  • 任务调度系统

  • GUI 事件处理


微信公众号

今日签到

点亮在社区的每一天
去签到