Skip to content

命令

更新: 6/22/2025 字数: 0 字 时长: 0 分钟

定义

命令模式 (Command Pattern) 将请求封装为对象,使你可以参数化客户端请求、队列请求、记录请求日志,以及支持可撤销操作。它解耦了请求发送者和接收者,使系统更灵活可扩展。

角色

  • 命令 (Command):声明执行操作的接口
  • 具体命令 (Concrete Command):将接收者绑定到动作
  • 调用者 (Invoker):要求命令执行请求
  • 接收者 (Receiver):知道如何执行操作
  • 客户端 (Client):创建具体命令并设置接收者

实现

基础命令模式

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

// 接收者:灯
public class Light {
    public void on() {
        System.out.println("灯已打开");
    }
    
    public void off() {
        System.out.println("灯已关闭");
    }
}

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

// 调用者:遥控器
public class RemoteControl {
    private Command[] onCommands;
    private Command[] offCommands;
    private Command undoCommand;
    
    public RemoteControl() {
        onCommands = new Command[7];
        offCommands = new Command[7];
        
        Command noCommand = new NoCommand();
        for (int i = 0; i < 7; 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 onButtonWasPushed(int slot) {
        onCommands[slot].execute();
        undoCommand = onCommands[slot];
    }
    
    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
        undoCommand = offCommands[slot];
    }
    
    public void undoButtonWasPushed() {
        undoCommand.undo();
    }
}

// 空命令(避免 null 检查)
public class NoCommand implements Command {
    @Override
    public void execute() {}
    
    @Override
    public void undo() {}
}

// 客户端使用
public class RemoteLoader {
    public static void main(String[] args) {
        RemoteControl remote = new RemoteControl();
        
        // 创建接收者
        Light livingRoomLight = new Light();
        
        // 创建命令
        LightOnCommand livingRoomLightOn = 
            new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOff = 
            new LightOffCommand(livingRoomLight);
        
        // 设置命令到遥控器
        remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        
        // 测试
        remote.onButtonWasPushed(0);
        remote.offButtonWasPushed(0);
        System.out.println("-- 撤销操作 --");
        remote.undoButtonWasPushed();
    }
}

宏命令(命令组合)

java
// 宏命令:一次执行多个命令
public 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();
        }
    }
}

// 使用示例
public class MacroCommandDemo {
    public static void main(String[] args) {
        // 创建接收者
        Light light = new Light();
        TV tv = new TV();
        
        // 创建命令
        LightOnCommand lightOn = new LightOnCommand(light);
        LightOffCommand lightOff = new LightOffCommand(light);
        TVOnCommand tvOn = new TVOnCommand(tv);
        TVOffCommand tvOff = new TVOffCommand(tv);
        
        // 创建宏命令
        Command[] partyOn = { lightOn, tvOn };
        Command[] partyOff = { lightOff, tvOff };
        
        MacroCommand partyOnMacro = new MacroCommand(partyOn);
        MacroCommand partyOffMacro = new MacroCommand(partyOff);
        
        // 使用宏命令
        RemoteControl remote = new RemoteControl();
        remote.setCommand(0, partyOnMacro, partyOffMacro);
        
        System.out.println("--- 执行宏命令开 ---");
        remote.onButtonWasPushed(0);
        
        System.out.println("--- 执行宏命令关 ---");
        remote.offButtonWasPushed(0);
        
        System.out.println("--- 撤销操作 ---");
        remote.undoButtonWasPushed();
    }
}

优缺点

优点:

  1. 解耦调用者和接收者
  2. 支持撤销/重做操作
  3. 支持命令组合(宏命令)
  4. 支持请求排队和日志记录
  5. 易于扩展新命令
  6. 实现请求延迟执行

缺点:

  1. 增加系统复杂度(多个新类)
  2. 命令对象可能过多
  3. 增加内存开销
  4. 实现完备的撤销/重做机制较复杂

应用场景

  1. GUI 按钮和菜单项
  2. 事务处理系统
  3. 多级撤销/重做功能
  4. 任务调度系统
  5. 日志记录系统
  6. 宏录制功能
  7. 异步任务队列

与其他模式的关系

  • 与责任链模式:命令可组成责任链
  • 与备忘录模式:配合实现撤销功能
  • 与原型模式:用于命令的复制
  • 与策略模式:命令对象可包含策略
  • 与组合模式:宏命令是组合模式的应用
  • 与观察者模式:命令执行可触发通知

JDK 中的命令模式

  1. Java 线程(Runnable 接口)
  2. Swing 的 Action 接口
  3. Java 定时器(TimerTask)
  4. Java 事务 API(JTA)
  5. Java 反射(Method.invoke)
  6. Lambda 表达式(函数式接口)
  7. Spring 的 CommandLineRunner

注意事项

  1. 命令粒度设计(避免过细或过粗)
  2. 命令对象生命周期管理
  3. 线程安全问题(共享命令状态)
  4. 撤销/重做实现策略
  5. 命令持久化设计
  6. 空命令处理(避免 null 检查)
  7. 命令参数化设计

贡献者

The avatar of contributor named as LI SIR LI SIR
The avatar of contributor named as wkwbk wkwbk

页面历史