命令模式

命令模式(Command Pattern)是一种行为型设计模式,它的核心思想是将请求封装为独立的对象,使请求的发送者和接收者解耦,并支持请求的队列化、日志记录、撤销/重做等扩展功能。


一、命令模式的核心结构

1. 核心角色

  • Command(命令接口):定义执行操作的接口(如execute()
  • ConcreteCommand(具体命令):实现命令接口,绑定接收者对象和动作
  • Invoker(调用者):触发命令的对象(如按钮、菜单项)
  • Receiver(接收者):真正执行操作的对象(如文件系统、数据库)
  • Client(客户端):创建具体命令并设置其接收者

2. 简单代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 命令接口
interface Command {
void execute();
}

// 接收者(实际执行操作的对象)
class Light {
public void turnOn() { System.out.println("灯已打开"); }
public void turnOff() { System.out.println("灯已关闭"); }
}

// 具体命令:开灯
class LightOnCommand implements Command {
private Light light;

public LightOnCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.turnOn();
}
}

// 调用者(遥控器按钮)
class RemoteControlButton {
private Command command;

public void setCommand(Command command) {
this.command = command;
}

public void press() {
command.execute(); // 触发命令
}
}

// 客户端使用
public class Client {
public static void main(String[] args) {
Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControlButton button = new RemoteControlButton();
button.setCommand(lightOn);
button.press(); // 输出:灯已打开
}
}

二、命令模式的关键应用场景

  1. 需要解耦请求发送者和接收者
    (如 GUI 按钮不应直接操作业务逻辑)

  2. 支持撤销/重做操作
    (记录命令历史,反向执行命令)

  3. 实现操作队列或延迟执行
    (如线程池任务调度)

  4. 支持事务操作
    (一组命令要么全部成功,要么全部回滚)


三、宏命令(Macro Command)

1. 什么是宏命令?

宏命令是组合多个命令的复合命令,通过一次调用触发多个命令的执行,常用于:

  • 批量操作(如「一键备份」触发文件压缩+上传+日志记录)
  • 事务处理(多个操作作为一个原子操作)

2. 宏命令实现示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 宏命令(实现命令接口的集合)
class MacroCommand implements Command {
private List<Command> commands = new ArrayList<>();

public void addCommand(Command cmd) {
commands.add(cmd);
}

@Override
public void execute() {
for (Command cmd : commands) {
cmd.execute(); // 依次执行所有命令
}
}
}

// 使用示例
public class MacroClient {
public static void main(String[] args) {
// 创建多个设备
Light light = new Light();
Speaker speaker = new Speaker(); // 假设有Speaker类

// 创建具体命令
Command lightOn = new LightOnCommand(light);
Command speakerOn = new SpeakerOnCommand(speaker); // 假设有SpeakerOnCommand

// 组合宏命令
MacroCommand morningRoutine = new MacroCommand();
morningRoutine.addCommand(lightOn);
morningRoutine.addCommand(speakerOn);

// 触发宏命令
RemoteControlButton button = new RemoteControlButton();
button.setCommand(morningRoutine);
button.press();
// 输出:
// 灯已打开
// 音响已启动
}
}

四、命令模式 vs 其他模式

对比维度 命令模式 策略模式
核心目的 封装请求 封装算法
关注点 请求的触发与执行解耦 算法的灵活替换
典型应用 撤销/重做、事务 支付方式、排序策略
扩展方向 支持命令组合(宏命令) 支持算法族的动态切换

五、命令模式的最佳实践

  1. 实现撤销操作
    在命令接口中增加undo()方法,保存执行前的状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    interface Command {
    void execute();
    void undo(); // 新增撤销方法
    }

    // 具体命令示例
    class LightOnCommand implements Command {
    private Light light;
    private boolean prevState; // 记录之前的状态

    public void execute() {
    prevState = light.isOn(); // 保存状态
    light.turnOn();
    }

    public void undo() {
    if (!prevState) light.turnOff(); // 恢复原状态
    }
    }
  2. 结合责任链模式
    实现命令的链式执行(一个命令执行后自动触发下一个命令)

  3. 与备忘录模式结合
    实现更复杂的状态回滚机制


总结:命令模式的本质

通过将「做什么」(请求内容)与「谁来做」(执行对象)、「何时做」(触发时机)分离,实现了:

  • 解耦:调用者无需知道接收者的存在
  • 扩展性:轻松添加新命令
  • 可编排性:通过宏命令实现复杂操作流

适用场景口诀
当你有需要解耦的请求操作,
或想要支持撤销、重做,
或是批量操作要组合,
命令模式是你可靠的选择!