命令模式把"请求"封装成对象,好处是可以排队、记录、撤销。线程池的 Runnable、编辑器的"撤销"就是它的落地。这篇讲清它怎么把"调用"变成"对象"。
一、解决什么问题:把请求变成对象
直接调用是 light.on()——调用完就没了,无法排队、无法撤销、无法记录。
命令模式的思路:把"开灯"这个动作封装成一个命令对象,这个对象可以被存储、排队、撤销。
二、核心结构
java
// 命令接口
interface Command {
void execute();
void undo(); // 撤销
}
// 接收者:真正干活的对象
class Light {
void on() { System.out.println("开灯"); }
void off() { System.out.println("关灯"); }
}
// 具体命令:封装"开灯"这个动作
class LightOnCommand implements Command {
private Light light;
LightOnCommand(Light light) { this.light = light; }
public void execute() { light.on(); }
public void undo() { light.off(); }
}
// 调用者:不关心具体命令,只负责触发
class RemoteControl {
private Command command;
void setCommand(Command c) { this.command = c; }
void press() { command.execute(); }
}
// 使用
RemoteControl remote = new RemoteControl();
remote.setCommand(new LightOnCommand(new Light()));
remote.press(); // 开灯关键:命令把"动作"变成了"对象"——LightOnCommand 可以被存进列表(命令队列)、被记录(日志)、被撤销(undo)。
三、核心价值
- 解耦:调用者(RemoteControl)不认识接收者(Light),只认识 Command
- 可排队:命令对象可以进队列,异步执行
- 可撤销:命令带 undo,支持撤销/重做
- 可记录:命令可以写日志,崩溃后重放
四、实际应用
- 线程池:
Runnable就是命令对象——你把"要执行的动作"封装成 Runnable,线程池排队执行 - 编辑器撤销:每个操作是一个命令,撤销 = 逆序执行 undo
- 菜单/快捷键:菜单项绑定命令对象
小结
- 命令把"请求"封装成对象,可排队、记录、撤销
- 调用者、接收者通过命令解耦
- 典型:线程池 Runnable、编辑器撤销
相关:《策略模式》(命令封装"动作",策略封装"算法",都是行为封装,但命令多一层"撤销/排队")。
