命令模式(Command Pattern)

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤离的操作。

行为结构

命令模式主要角色:

  1. Command(命令接口): 定义执行操作的接口,通常包含一个execute()方法。
  2. ConcreteCommand(具体命令类): 实现Command接口,绑定具体的接受者对象(Receiver),并在execute()方法中调用接受者的相应方法。
  3. Invoker(调用者):负责调用命令对象来执行请求。
  4. Receiver(接收者):实际执行命令的对象,包含业务逻辑的具体实现。
  5. Client(客户端):创建具体的命令对象,并设置其接收者。

示例代码如下:

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
// Command 接口
public interface Command {
void execute();
}
// Reciver 类
public class Light {
public void on();
public void off();
}
// ConcreteCommand 实现
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.on();
}
}
// Invoker 类
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// Client 使用
Light light = new Light(); // Receiver
Command command = new LightOnCommand(light); // ConcreteCommand

RemoteControl remoteControl = new RemoteControl(); // Invoke
remoteControl.setCommand(command);
remoteControl.pressButton(); // 执行命令

特点与应用场景

  • 解耦请求发送者和接收者: 通过命令对象,请求发送者无需指导接收者及其具体操作,只需触发命令即可。
  • 支持撤销/重做: 可以通过记录命令历史实现撤销或重做功能。
  • 支持队列和日志: 可以将命令对象存储在队列中,按需执行;也可以记录日志以恢复状态。
  • 适合场景: GUI操作、事务回滚、人物队列等需要解耦和扩展性的场景。
  1. 优点

    • 提高了系统的灵活性和可扩展性。
    • 支持多种高级功能(如撤销、日志记录)。
  2. 缺点

    • 可能增加系统的复杂度,因为需要为每个操作定义独立的命令类。

CQRS中Command的区别

对比点 命令模式中的Command CQRS中的Command
目的 封装一个操作及其参数,实现请求的排队、撤销等 表示对系统状态进行更改的操作,用于写模型处理
所属架构 行为型设计模式 架构风格的一部分,常配合事件溯源(Event Sourcing)使用;
职责 调用Receiver的方法执行具体逻辑 发送到CommandHandler,触发聚合根修改并产生领域事件