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();
    }
}

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

相关推荐
roman_日积跬步-终至千里5 分钟前
【Java并发】多线程/并发问题集
java·开发语言
それども25 分钟前
什么是MalformedStreamException,和WebKitFormBoundary有什么关系
java
思想在飞肢体在追1 小时前
Springboot项目配置Nacos
java·spring boot·后端·nacos
cyforkk1 小时前
09、Java 基础硬核复习:异常处理(容错机制)的核心逻辑与面试考点
java·数据库·面试
??(lxy)1 小时前
java高性能无锁队列——MpscLinkedQueue
java·开发语言
数研小生1 小时前
Full Analysis of Taobao Item Detail API taobao.item.get
java·服务器·前端
Wang15302 小时前
Java编程基础与面向对象核心概念
java
毕设源码-郭学长2 小时前
【开题答辩全过程】以 康复管理系统为例,包含答辩的问题和答案
java
毅炼2 小时前
hot100打卡——day17
java·数据结构·算法·leetcode·深度优先
winfreedoms2 小时前
java-网络编程——黑马程序员学习笔记
java·网络·学习