Deepeek用大白话讲解 --> 命令模式(企业级场景1,智能家居遥控器2,撤销重做3,宏命令4)

命令模式(Command)大白话讲解

一句话概括

就像餐厅点餐:你(客户)告诉服务员(调用者)要什么菜,服务员把订单(命令)交给厨师(接收者),厨师按订单做菜


现实生活比喻

场景1:餐厅点餐

  • :顾客(客户端)
  • 服务员:调用者(Invoker)
  • 菜单/订单:命令(Command)
  • 厨师:接收者(Receiver)
  • 过程:你告诉服务员要什么菜 → 服务员写下订单 → 厨师按订单做菜

场景2:遥控器

  • :使用者
  • 遥控器按钮:调用者
  • 按钮命令:命令对象
  • 电视/空调:接收者
  • 过程:你按遥控器按钮 → 遥控器执行对应命令 → 电视/空调响应

完整代码示例

场景1:智能家居遥控器

java 复制代码
/**
 * 命令模式 - 智能家居示例
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("=== 智能家居控制系统 ===");
        
        // 创建接收者(家电设备)
        Light livingRoomLight = new Light("客厅灯");
        Light bedroomLight = new Light("卧室灯");
        Fan ceilingFan = new Fan("吊扇");
        Door garageDoor = new Door("车库门");
        Stereo stereo = new Stereo("音响");
        
        // 创建具体命令
        Command lightOnCommand = new LightOnCommand(livingRoomLight);
        Command lightOffCommand = new LightOffCommand(livingRoomLight);
        Command fanOnCommand = new FanOnCommand(ceilingFan);
        Command fanOffCommand = new FanOffCommand(ceilingFan);
        Command doorOpenCommand = new DoorOpenCommand(garageDoor);
        Command doorCloseCommand = new DoorCloseCommand(garageDoor);
        Command stereoOnCommand = new StereoOnCommand(stereo);
        Command stereoOffCommand = new StereoOffCommand(stereo);
        
        // 创建宏命令(一键执行多个命令)
        Command[] partyOnCommands = {lightOnCommand, stereoOnCommand, fanOnCommand};
        Command[] partyOffCommands = {lightOffCommand, stereoOffCommand, fanOffCommand};
        Command partyModeOnCommand = new MacroCommand(partyOnCommands);
        Command partyModeOffCommand = new MacroCommand(partyOffCommands);
        
        // 创建调用者(遥控器)
        RemoteControl remote = new RemoteControl();
        
        // 设置遥控器按钮
        remote.setCommand(0, lightOnCommand, lightOffCommand);
        remote.setCommand(1, fanOnCommand, fanOffCommand);
        remote.setCommand(2, doorOpenCommand, doorCloseCommand);
        remote.setCommand(3, stereoOnCommand, stereoOffCommand);
        remote.setCommand(4, partyModeOnCommand, partyModeOffCommand);
        
        // 使用遥控器
        System.out.println("\n--- 测试遥控器按钮 ---");
        remote.onButtonPressed(0);  // 打开客厅灯
        remote.offButtonPressed(0); // 关闭客厅灯
        
        remote.onButtonPressed(1);  // 打开吊扇
        remote.offButtonPressed(1); // 关闭吊扇
        
        System.out.println("\n--- 测试一键派对模式 ---");
        remote.onButtonPressed(4);  // 开启派对模式
        
        System.out.println("\n--- 测试撤销功能 ---");
        remote.onButtonPressed(0);  // 打开客厅灯
        remote.onButtonPressed(1);  // 打开吊扇
        remote.undoButtonPressed(); // 撤销上一个命令(关闭吊扇)
        remote.undoButtonPressed(); // 撤销上上个命令(关闭客厅灯)
        
        System.out.println("\n--- 测试宏命令 ---");
        remote.onButtonPressed(4);  // 开启派对模式(同时打开灯、音响、风扇)
        remote.offButtonPressed(4); // 关闭派对模式(同时关闭灯、音响、风扇)
    }
}

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

/**
 * 接收者 - 电灯
 */
class Light {
    private String location;
    private boolean isOn = false;
    
    public Light(String location) {
        this.location = location;
    }
    
    public void on() {
        isOn = true;
        System.out.println(location + " 打开");
    }
    
    public void off() {
        isOn = false;
        System.out.println(location + " 关闭");
    }
    
    public boolean isOn() {
        return isOn;
    }
}

/**
 * 具体命令 - 开灯命令
 */
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();
    }
}

/**
 * 具体命令 - 关灯命令
 */
class LightOffCommand implements Command {
    private Light light;
    
    public LightOffCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() {
        light.off();
    }
    
    @Override
    public void undo() {
        light.on();
    }
}

/**
 * 接收者 - 吊扇
 */
class Fan {
    private String location;
    private boolean isOn = false;
    
    public Fan(String location) {
        this.location = location;
    }
    
    public void on() {
        isOn = true;
        System.out.println(location + " 打开");
    }
    
    public void off() {
        isOn = false;
        System.out.println(location + " 关闭");
    }
}

/**
 * 具体命令 - 开风扇命令
 */
class FanOnCommand implements Command {
    private Fan fan;
    
    public FanOnCommand(Fan fan) {
        this.fan = fan;
    }
    
    @Override
    public void execute() {
        fan.on();
    }
    
    @Override
    public void undo() {
        fan.off();
    }
}

/**
 * 具体命令 - 关风扇命令
 */
class FanOffCommand implements Command {
    private Fan fan;
    
    public FanOffCommand(Fan fan) {
        this.fan = fan;
    }
    
    @Override
    public void execute() {
        fan.off();
    }
    
    @Override
    public void undo() {
        fan.on();
    }
}

/**
 * 接收者 - 门
 */
class Door {
    private String location;
    
    public Door(String location) {
        this.location = location;
    }
    
    public void open() {
        System.out.println(location + " 打开");
    }
    
    public void close() {
        System.out.println(location + " 关闭");
    }
}

/**
 * 具体命令 - 开门命令
 */
class DoorOpenCommand implements Command {
    private Door door;
    
    public DoorOpenCommand(Door door) {
        this.door = door;
    }
    
    @Override
    public void execute() {
        door.open();
    }
    
    @Override
    public void undo() {
        door.close();
    }
}

/**
 * 具体命令 - 关门命令
 */
class DoorCloseCommand implements Command {
    private Door door;
    
    public DoorCloseCommand(Door door) {
        this.door = door;
    }
    
    @Override
    public void execute() {
        door.close();
    }
    
    @Override
    public void undo() {
        door.open();
    }
}

/**
 * 接收者 - 音响
 */
class Stereo {
    private String location;
    
    public Stereo(String location) {
        this.location = location;
    }
    
    public void on() {
        System.out.println(location + " 打开");
    }
    
    public void off() {
        System.out.println(location + " 关闭");
    }
}

/**
 * 具体命令 - 开音响命令
 */
class StereoOnCommand implements Command {
    private Stereo stereo;
    
    public StereoOnCommand(Stereo stereo) {
        this.stereo = stereo;
    }
    
    @Override
    public void execute() {
        stereo.on();
    }
    
    @Override
    public void undo() {
        stereo.off();
    }
}

/**
 * 具体命令 - 关音响命令
 */
class StereoOffCommand implements Command {
    private Stereo stereo;
    
    public StereoOffCommand(Stereo stereo) {
        this.stereo = stereo;
    }
    
    @Override
    public void execute() {
        stereo.off();
    }
    
    @Override
    public void undo() {
        stereo.on();
    }
}

/**
 * 宏命令 - 一次执行多个命令
 */
class MacroCommand implements Command {
    private Command[] commands;
    
    public MacroCommand(Command[] commands) {
        this.commands = commands;
    }
    
    @Override
    public void execute() {
        for (Command command : commands) {
            command.execute();
        }
    }
    
    @Override
    public void undo() {
        // 反序执行撤销
        for (int i = commands.length - 1; i >= 0; i--) {
            commands[i].undo();
        }
    }
}

/**
 * 调用者 - 遥控器
 */
class RemoteControl {
    private Command[] onCommands;
    private Command[] offCommands;
    private Command undoCommand;
    
    public RemoteControl() {
        onCommands = new Command[5];
        offCommands = new Command[5];
        
        // 初始化所有按钮为空命令
        Command noCommand = new NoCommand();
        for (int i = 0; i < 5; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }
    
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    
    public void onButtonPressed(int slot) {
        onCommands[slot].execute();
        undoCommand = onCommands[slot];  // 记录最后执行的命令用于撤销
    }
    
    public void offButtonPressed(int slot) {
        offCommands[slot].execute();
        undoCommand = offCommands[slot];  // 记录最后执行的命令用于撤销
    }
    
    public void undoButtonPressed() {
        System.out.println("--- 撤销上一个操作 ---");
        undoCommand.undo();
    }
}

/**
 * 空命令(用于初始化)
 */
class NoCommand implements Command {
    @Override
    public void execute() {
        System.out.println("该按钮未设置命令");
    }
    
    @Override
    public void undo() {
        System.out.println("没有可撤销的操作");
    }
}

运行结果

复制代码
=== 智能家居控制系统 ===

--- 测试遥控器按钮 ---
客厅灯 打开
客厅灯 关闭
吊扇 打开
吊扇 关闭

--- 测试一键派对模式 ---
客厅灯 打开
音响 打开
吊扇 打开

--- 测试撤销功能 ---
客厅灯 打开
吊扇 打开
--- 撤销上一个操作 ---
吊扇 关闭
--- 撤销上一个操作 ---
客厅灯 关闭

--- 测试宏命令 ---
客厅灯 打开
音响 打开
吊扇 打开
客厅灯 关闭
音响 关闭
吊扇 关闭

场景2:文本编辑器(支持撤销/重做)

java 复制代码
/**
 * 命令模式 - 文本编辑器示例(支持撤销/重做)
 */
public class TextEditorExample {
    public static void main(String[] args) {
        System.out.println("=== 文本编辑器(支持撤销/重做) ===");
        
        // 创建接收者(文档)
        Document document = new Document();
        
        // 创建命令历史记录
        CommandHistory history = new CommandHistory();
        
        // 创建命令
        Command insertCommand1 = new InsertTextCommand(document, "Hello, ", 0);
        Command insertCommand2 = new InsertTextCommand(document, "World!", 7);
        Command deleteCommand = new DeleteTextCommand(document, 5, 2);
        Command updateCommand = new UpdateTextCommand(document, "Design Patterns", 7, 6);
        
        // 执行命令
        System.out.println("\n--- 执行命令 ---");
        executeCommand(insertCommand1, history);
        System.out.println("文档内容: " + document.getContent());
        
        executeCommand(insertCommand2, history);
        System.out.println("文档内容: " + document.getContent());
        
        executeCommand(deleteCommand, history);
        System.out.println("文档内容: " + document.getContent());
        
        executeCommand(updateCommand, history);
        System.out.println("文档内容: " + document.getContent());
        
        // 撤销操作
        System.out.println("\n--- 撤销操作 ---");
        undoLastCommand(history);
        System.out.println("文档内容: " + document.getContent());
        
        undoLastCommand(history);
        System.out.println("文档内容: " + document.getContent());
        
        // 重做操作
        System.out.println("\n--- 重做操作 ---");
        redoLastCommand(history);
        System.out.println("文档内容: " + document.getContent());
        
        redoLastCommand(history);
        System.out.println("文档内容: " + document.getContent());
        
        // 显示历史记录
        history.showHistory();
    }
    
    private static void executeCommand(Command command, CommandHistory history) {
        command.execute();
        history.add(command);
    }
    
    private static void undoLastCommand(CommandHistory history) {
        history.undo();
    }
    
    private static void redoLastCommand(CommandHistory history) {
        history.redo();
    }
}

/**
 * 接收者 - 文档
 */
class Document {
    private StringBuilder content = new StringBuilder();
    
    public void insert(String text, int position) {
        content.insert(position, text);
    }
    
    public void delete(int position, int length) {
        content.delete(position, position + length);
    }
    
    public void update(String newText, int position, int length) {
        content.replace(position, position + length, newText);
    }
    
    public String getContent() {
        return content.toString();
    }
}

/**
 * 具体命令 - 插入文本命令
 */
class InsertTextCommand implements Command {
    private Document document;
    private String text;
    private int position;
    
    public InsertTextCommand(Document document, String text, int position) {
        this.document = document;
        this.text = text;
        this.position = position;
    }
    
    @Override
    public void execute() {
        document.insert(text, position);
        System.out.println("执行: 在位置 " + position + " 插入文本 \"" + text + "\"");
    }
    
    @Override
    public void undo() {
        document.delete(position, text.length());
        System.out.println("撤销: 删除在位置 " + position + " 插入的文本 \"" + text + "\"");
    }
}

/**
 * 具体命令 - 删除文本命令
 */
class DeleteTextCommand implements Command {
    private Document document;
    private int position;
    private int length;
    private String deletedText;  // 用于撤销时恢复
    
    public DeleteTextCommand(Document document, int position, int length) {
        this.document = document;
        this.position = position;
        this.length = length;
    }
    
    @Override
    public void execute() {
        // 注意:这里需要先保存被删除的文本,但为了简化我们只记录位置和长度
        System.out.println("执行: 从位置 " + position + " 删除 " + length + " 个字符");
        document.delete(position, length);
    }
    
    @Override
    public void undo() {
        // 注意:实际实现中需要保存被删除的文本才能恢复
        System.out.println("撤销: 无法恢复已删除的文本(简化实现)");
    }
}

/**
 * 具体命令 - 更新文本命令
 */
class UpdateTextCommand implements Command {
    private Document document;
    private String newText;
    private int position;
    private int length;
    private String oldText;  // 用于撤销时恢复
    
    public UpdateTextCommand(Document document, String newText, int position, int length) {
        this.document = document;
        this.newText = newText;
        this.position = position;
        this.length = length;
    }
    
    @Override
    public void execute() {
        System.out.println("执行: 从位置 " + position + " 更新 " + length + " 个字符为 \"" + newText + "\"");
        document.update(newText, position, length);
    }
    
    @Override
    public void undo() {
        System.out.println("撤销: 恢复更新的文本(简化实现)");
    }
}

/**
 * 命令历史记录(支持撤销/重做)
 */
class CommandHistory {
    private Stack<Command> undoStack = new Stack<>();
    private Stack<Command> redoStack = new Stack<>();
    
    public void add(Command command) {
        undoStack.push(command);
        redoStack.clear();  // 执行新命令时清空重做栈
    }
    
    public void undo() {
        if (!undoStack.isEmpty()) {
            Command command = undoStack.pop();
            command.undo();
            redoStack.push(command);
        } else {
            System.out.println("没有可撤销的命令");
        }
    }
    
    public void redo() {
        if (!redoStack.isEmpty()) {
            Command command = redoStack.pop();
            command.execute();
            undoStack.push(command);
        } else {
            System.out.println("没有可重做的命令");
        }
    }
    
    public void showHistory() {
        System.out.println("\n=== 命令历史 ===");
        System.out.println("撤销栈大小: " + undoStack.size());
        System.out.println("重做栈大小: " + redoStack.size());
    }
}

运行结果

复制代码
=== 文本编辑器(支持撤销/重做) ===

--- 执行命令 ---
执行: 在位置 0 插入文本 "Hello, "
文档内容: Hello, 
执行: 在位置 7 插入文本 "World!"
文档内容: Hello, World!
执行: 从位置 5 删除 2 个字符
文档内容: Hello World!
执行: 从位置 7 更新 6 个字符为 "Design Patterns"
文档内容: Hello Design Patterns

--- 撤销操作 ---
撤销: 恢复更新的文本(简化实现)
文档内容: Hello Design Patterns
撤销: 无法恢复已删除的文本(简化实现)
文档内容: Hello Design Patterns

--- 重做操作 ---
执行: 从位置 5 删除 2 个字符
文档内容: Hello Design Patterns
执行: 从位置 7 更新 6 个字符为 "Design Patterns"
文档内容: Hello Design Patterns

=== 命令历史 ===
撤销栈大小: 2
重做栈大小: 0

命令模式的核心结构

复制代码
      Client(客户端)
         ↓ 创建
      Command(命令接口) ← Invoker(调用者)
         ↑ 实现                 ↓ 执行
ConcreteCommand(具体命令) → Receiver(接收者)

关键特征:

  • 命令对象:封装请求的所有信息(接收者、方法、参数)
  • 调用者:触发命令执行,不知道具体实现
  • 接收者:真正执行操作的对象
  • 解耦:调用者和接收者完全解耦

命令模式的核心优势

1. 解耦调用者和接收者

java 复制代码
// 遥控器(调用者)不知道具体设备(接收者)
remote.onButtonPressed(0); // 只知道执行命令,不知道是开灯还是开风扇

2. 支持撤销/重做

java 复制代码
// 命令对象可以记录状态,支持撤销
command.execute();  // 执行
command.undo();     // 撤销

3. 支持命令队列和日志

java 复制代码
// 命令可以排队执行
queue.add(command1);
queue.add(command2);
queue.processAll();

// 可以记录命令日志用于恢复
log.add(command);

4. 支持宏命令(组合命令)

java 复制代码
// 多个命令组合成一个命令
Command macro = new MacroCommand(command1, command2, command3);
macro.execute(); // 一次执行所有命令

适用场景(大白话版)

适合用命令模式的场景:

  1. 需要撤销/重做功能

    java 复制代码
    // 文本编辑器、绘图软件、IDE等
    // 每个操作都是一个命令对象
  2. 需要将操作排队或记录日志

    java 复制代码
    // 任务调度系统、事务系统
    // 命令可以序列化、持久化
  3. 需要支持宏命令

    java 复制代码
    // 批处理操作、一键执行多个操作
    // 游戏中的宏按键、IDE的宏录制
  4. 需要解耦调用者和接收者

    java 复制代码
    // GUI按钮点击事件
    // 菜单项点击事件
    // 遥控器按键

不适合的场景:

  1. 简单操作:如果操作很简单,直接调用方法即可
  2. 性能敏感:命令对象创建有开销
  3. 不需要撤销/队列功能:如果不需要这些高级功能

优缺点

优点:

  • 解耦:调用者和接收者完全解耦
  • 灵活:可以轻松添加新命令
  • 支持撤销/重做:天然支持操作历史
  • 支持组合命令:可以实现宏命令
  • 支持命令队列:可以排队执行命令

缺点:

  • 复杂度增加:每个命令都需要一个类
  • 性能开销:创建大量命令对象有开销
  • 可能过度设计:简单场景下显得复杂

实际应用案例

1. GUI事件处理

java 复制代码
// Java Swing/AWT中的ActionListener
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // 这就是一个命令
        saveDocument();
    }
});

2. 线程池/任务队列

java 复制代码
// Java的Runnable就是命令模式
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(new Runnable() {  // 命令对象
    public void run() {
        // 执行任务
    }
});

3. 数据库事务

java 复制代码
// 事务中的每个操作都是一个命令
Transaction tx = database.beginTransaction();
tx.execute(new InsertCommand(data1));
tx.execute(new UpdateCommand(data2));
tx.execute(new DeleteCommand(data3));
tx.commit();  // 一次执行所有命令
tx.rollback(); // 撤销所有命令

4. 游戏开发

java 复制代码
// 游戏中的输入处理
InputHandler handler = new InputHandler();
handler.bind(KeyEvent.VK_SPACE, new JumpCommand(player));
handler.bind(KeyEvent.VK_A, new MoveLeftCommand(player));
handler.bind(KeyEvent.VK_D, new MoveRightCommand(player));

与其它模式对比

模式 目的 关键区别
命令模式 封装请求 将请求封装为对象,支持撤销/队列
策略模式 封装算法 封装算法,可以相互替换
责任链模式 传递请求 请求在链中传递,直到被处理
备忘录模式 保存状态 保存对象状态,用于恢复

总结

命令模式就是:

  • 订单系统:顾客下单 → 厨房做菜
  • 遥控器:你按按钮 → 设备响应
  • 军事命令:将军下令 → 士兵执行
  • 编程接口:API调用 → 系统执行

核心口诀:

请求需要封装好,

调用执行要解耦。

撤销重做是强项,

队列日志都能搞!

就像现实中的:

  • 🍽️ 餐厅点餐:菜单(命令)连接顾客(客户端)和厨师(接收者)
  • 🎮 游戏手柄:按键(命令)连接玩家(客户端)和游戏角色(接收者)
  • 📝 办公流程:申请表(命令)连接申请人(客户端)和审批人(接收者)
  • 🏦 银行交易:交易指令(命令)连接客户(客户端)和银行系统(接收者)

记住:当你需要将请求封装为对象,并支持撤销、排队、日志或事务功能时,考虑使用命令模式!

相关推荐
小灰灰搞电子16 小时前
Qt 重写QRadioButton实现动态radioButton源码分享
开发语言·qt·命令模式
三佛科技-134163842121 天前
点焊机方案开发,点焊机MCU控制方案设计
单片机·嵌入式硬件·智能家居·pcb工艺
飞睿科技1 天前
ESP Audio Effects音频库迎来专业升级,v1.2.0 新增动态控制核心
人工智能·物联网·ffmpeg·智能家居·语音识别·乐鑫科技·esp
躺柒1 天前
读捍卫隐私07智能家居
信息安全·智能家居·数据安全·隐私·隐私保护·互联网隐私保护
小灰灰搞电子2 天前
Qt 实现炫酷锁屏源码分享
开发语言·qt·命令模式
一只小bit2 天前
Qt Widget 控件介绍:覆盖常用属性及API
开发语言·c++·qt·命令模式·cpp
iFlow_AI3 天前
iFlow CLI 实战案例|生产级 Agent 聊天应用——Chatbot
交互·ai编程·命令模式·iflow·iflow cli·iflowcli
知秋一叶1233 天前
Miloco 添加 RTSP 协议支持(非官方正式版)
人工智能·智能家居
三佛科技-134163842124 天前
FT8353系列(FT8353A/B/C/CD/DD/K/KD/PD)隔离型LED恒流驱动IC芯片 典型应用电路
单片机·物联网·智能家居·pcb工艺