命令模式
命令模式把一个请求封装成对象,使请求可以被保存、排队、撤销、重试或记录。
一句话理解:把“要做的事”变成一个对象。
解决什么问题
普通调用是直接执行:
java
service.createOrder();这种方式简单,但如果你希望支持下面能力,就会不够用:
- 请求排队执行。
- 操作日志记录。
- 失败重试。
- 撤销和恢复。
- 延迟执行。
- 把请求发送到其他线程或消息队列。
命令模式把请求封装为命令对象,让执行时机和执行者解耦。
基本结构
text
Client -> Command -> Receiver
Invoker -> Command.execute()角色:
Command:命令接口。ConcreteCommand:具体命令。Receiver:真正执行业务的人。Invoker:触发命令执行的人。
Java 示例
接收者:
java
class Light {
void on() {
System.out.println("light on");
}
void off() {
System.out.println("light off");
}
}命令接口:
java
interface Command {
void execute();
}具体命令:
java
class LightOnCommand implements Command {
private final Light light;
LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
}
class LightOffCommand implements Command {
private final Light light;
LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
}调用者:
java
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void press() {
command.execute();
}
}使用:
java
Light light = new Light();
RemoteControl remote = new RemoteControl();
remote.setCommand(new LightOnCommand(light));
remote.press();
remote.setCommand(new LightOffCommand(light));
remote.press();支持撤销
命令对象可以保存撤销逻辑:
java
interface UndoableCommand {
void execute();
void undo();
}例如编辑器中的撤销、重做,本质上就是把用户操作保存成命令历史。
使用场景
- 任务队列。
- 异步执行。
- 操作日志。
- 撤销/重做。
- 事务脚本。
- 菜单按钮和快捷键绑定操作。
优点
- 请求发起者和执行者解耦。
- 命令可以排队、记录、重试。
- 容易扩展新命令。
- 适合实现撤销和恢复。
缺点
- 命令类数量可能很多。
- 简单调用场景会显得繁琐。
- 如果命令对象设计太大,会变成另一种业务服务。
实战注意
在业务系统里,命令模式常见形态是 Command、CommandHandler、消息任务、定时任务。它的价值不在于名字,而在于把请求封装成可以被调度和管理的对象。