Java设计模式之命令模式详解

Java设计模式之命令模式详解


一、命令模式核心思想

核心目标将请求封装为对象,使请求的发送者与接收者解耦。支持请求的排队、记录、撤销等操作,如同餐厅点餐系统:顾客(发送者)→ 订单(命令对象)→ 厨师(接收者)。


二、命令模式类图(Mermaid)

持有 调用 创建 创建 配置 Invoker -command: Command +setCommand(Command) +executeCommand() <<interface>> Command +execute() +undo() ConcreteCommand -receiver: Receiver -state +execute() +undo() Receiver +action() Client


三、代码实现示例

1. 智能家居控制场景

java 复制代码
// 接收者:灯光
class Light {
    private boolean isOn = false;
    
    public void turnOn() {
        isOn = true;
        System.out.println("灯光已打开");
    }
    
    public void turnOff() {
        isOn = false;
        System.out.println("灯光已关闭");
    }
    
    public boolean isOn() { return isOn; }
}

// 命令接口
interface Command {
    void execute();
    void undo();
}

// 具体命令:开灯
class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOn();
    }
    
    public void undo() {
        light.turnOff();
    }
}

// 调用者:遥控器按钮
class RemoteControlButton {
    private Command command;
    private Command lastCommand;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
        lastCommand = command;
    }
    
    public void pressUndo() {
        if (lastCommand != null) {
            lastCommand.undo();
            lastCommand = null;
        }
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        Light livingRoomLight = new Light();
        Command lightOn = new LightOnCommand(livingRoomLight);
        
        RemoteControlButton button = new RemoteControlButton();
        button.setCommand(lightOn);
        
        button.pressButton();   // 输出:灯光已打开
        button.pressUndo();     // 输出:灯光已关闭
    }
}

四、模式优缺点分析

✅ 优势

  • 解耦请求者与执行者:发送者无需知道接收者细节
  • 支持高级操作:轻松实现撤销/重做、事务、队列等功能
  • 灵活扩展:新增命令无需修改已有代码
  • 组合命令:支持宏命令(批量执行)

❌ 缺点

  • 类数量增加:每个命令都需要单独类
  • 过度设计风险:简单操作可能不适用

五、典型应用场景

  1. GUI操作:菜单项点击事件处理
  2. 事务系统:数据库操作回滚
  3. 任务队列:线程池任务调度
  4. 宏命令:批量执行操作(如IDE快捷键)
  5. 游戏控制:角色动作的撤销/重做

六、Mermaid序列图(命令执行流程)

Client Invoker Command Receiver setCommand(Command) executeCommand() execute() action() Client Invoker Command Receiver


七、命令模式 vs 其他模式

对比模式 核心区别
策略模式 封装算法,行为可替换
职责链模式 请求沿链传递直到被处理
备忘录模式 保存对象状态用于恢复

八、高级应用技巧

1. 宏命令(批量操作)

java 复制代码
class MacroCommand implements Command {
    private List<Command> commands = new ArrayList<>();
    
    public void add(Command cmd) {
        commands.add(cmd);
    }
    
    public void execute() {
        commands.forEach(Command::execute);
    }
    
    public void undo() {
        // 逆序执行撤销
        for (int i = commands.size()-1; i >=0; i--) {
            commands.get(i).undo();
        }
    }
}

// 使用示例
MacroCommand partyMode = new MacroCommand();
partyMode.add(new LightOnCommand(light));
partyMode.add(new MusicPlayCommand(speaker));
partyMode.execute();  // 同时执行开灯和播放音乐

2. 命令历史记录(支持多级撤销)

java 复制代码
class CommandHistory {
    private Stack<Command> history = new Stack<>();
    
    public void push(Command cmd) {
        history.push(cmd);
    }
    
    public Command pop() {
        return history.pop();
    }
    
    public void undoAll() {
        while (!history.isEmpty()) {
            history.pop().undo();
        }
    }
}

九、实际框架应用案例

1. Java Swing的Action接口

<<interface>> Action +actionPerformed(ActionEvent) AbstractAction +actionPerformed(ActionEvent) JButton +setAction(Action)

2. Spring的JdbcTemplate

java 复制代码
// 命令模式变体:模板方法+回调命令
jdbcTemplate.execute(new ConnectionCallback<Object>() {
    public Object doInConnection(Connection conn) {
        // 执行SQL命令
        return null;
    }
});

十、常见问题解答

Q1:如何防止命令对象膨胀?

  • 使用Lambda表达式(Java 8+)
java 复制代码
button.setCommand(() -> light.turnOn());

Q2:如何处理命令参数?

java 复制代码
class DimLightCommand implements Command {
    private Light light;
    private int prevBrightness;
    private int newBrightness;
    
    public DimLightCommand(Light light, int brightness) {
        this.light = light;
        this.newBrightness = brightness;
    }
    
    public void execute() {
        prevBrightness = light.getBrightness();
        light.setBrightness(newBrightness);
    }
    
    public void undo() {
        light.setBrightness(prevBrightness);
    }
}

Q3:命令模式如何支持异步?

java 复制代码
class AsyncCommand implements Command {
    private Command command;
    
    public void execute() {
        new Thread(command::execute).start();
    }
}

如果文章对您有帮助,请帮忙点关注支持一下吧,谢谢啦!

相关推荐
毕设源码-朱学姐3 小时前
【开题答辩全过程】以 工厂能耗分析平台的设计与实现为例,包含答辩的问题和答案
java·vue.js
Spring AI学习4 小时前
Spring AI深度解析(9/50):可观测性与监控体系实战
java·人工智能·spring
java1234_小锋5 小时前
Spring IoC的实现机制是什么?
java·后端·spring
xqqxqxxq6 小时前
背单词软件技术笔记(V2.0扩展版)
java·笔记·python
消失的旧时光-19436 小时前
深入理解 Java 线程池(二):ThreadPoolExecutor 执行流程 + 运行状态 + ctl 原理全解析
java·开发语言
哈哈老师啊6 小时前
Springboot学生综合测评系统hxtne(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·数据库·spring boot
4311媒体网6 小时前
帝国cms调用文章内容 二开基本操作
java·开发语言·php
zwxu_6 小时前
Nginx NIO对比Java NIO
java·nginx·nio
可观测性用观测云7 小时前
Pyroscope Java 接入最佳实践
java
气π8 小时前
【JavaWeb】——(若依 + AI)-基础学习笔记
java·spring boot·笔记·学习·java-ee·mybatis·ruoyi