一句话定义命令模式: 将请求封装为对象,实现请求调用者与执行者的解耦。 用代码说话,拒绝废话!
一、适用场景(直接上代码案例)
场景:智能家居遥控器
假设我们需要控制灯、空调、音响等设备,要求支持:
- 一键执行多个设备操作
- 支持操作撤销(Undo)
- 支持宏命令(批量操作)
传统写法痛点:
// 调用者直接依赖具体设备
Light light = new Light();
AirConditioner ac = new AirConditioner();
// 实现“回家模式”(开灯+开空调)
light.on();
ac.on();
// 问题1:撤销操作需记录状态,代码混乱
// 问题2:新增设备需修改调用代码,违反开闭原则二、命令模式解决方案(附完整代码)
1. 核心角色
- Command(命令接口)
- ConcreteCommand(具体命令)
- Invoker(调用者/遥控器)
- Receiver(接收者/设备)
2. 代码实现
// 1. 命令接口
interface Command {
void execute();
void undo(); // 支持撤销
}
// 2. 接收者(设备实现)
class Light {
void on() { System.out.println("开灯"); }
void off() { System.out.println("关灯"); }
}
class AirConditioner {
void on() { System.out.println("开空调"); }
void off() { System.out.println("关空调"); }
}
// 3. 具体命令(封装操作)
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(); } // 撤销=关灯
}
class ACOnCommand implements Command {
private AirConditioner ac;
public ACOnCommand(AirConditioner ac) { this.ac = ac; }
@Override
public void execute() { ac.on(); }
@Override
public void undo() { ac.off(); }
}
// 4. 宏命令(批量操作)
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();
}
@Override
public void undo() {
// 逆序撤销
for (int i = commands.size() - 1; i >= 0; i--) {
commands.get(i).undo();
}
}
}
// 5. 调用者(遥控器)
class RemoteControl {
private Command command;
public void setCommand(Command command) { this.command = command; }
public void pressButton() { command.execute(); }
public void pressUndo() { command.undo(); }
}
// 6. 客户端使用
public class Client {
public static void main(String[] args) {
// 创建设备
Light light = new Light();
AirConditioner ac = new AirConditioner();
// 创建命令
Command lightOn = new LightOnCommand(light);
Command acOn = new ACOnCommand(ac);
// 创建宏命令(回家模式:开灯+开空调)
MacroCommand homeMode = new MacroCommand();
homeMode.addCommand(lightOn);
homeMode.addCommand(acOn);
// 遥控器绑定宏命令
RemoteControl remote = new RemoteControl();
remote.setCommand(homeMode);
// 一键执行
remote.pressButton(); // 输出:开灯 开空调
remote.pressUndo(); // 输出:关空调 关灯(逆序撤销)
}
}三、四大核心应用场景
- 需要解耦调用者与执行者
- 遥控器(Invoker)不直接操作设备,通过Command接口调用。
- 支持撤销/重做操作
- 每个Command实现undo()方法(如编辑器撤销功能)。
- 需要支持事务操作
- 宏命令保证批量操作原子性(全部成功或全部撤销)。
- 队列请求/延迟执行
- 将Command存入队列,线程池异步执行(如订单处理系统)。
四、优缺点(表格对比)
优点 | 缺点 |
解耦调用者与执行者 | 类爆炸 |
支持撤销/重做 | 过度设计 |
易于扩展新命令 | |
支持组合命令 |
五、实战经验总结
- 优先使用场景
- 需要撤销/重做功能(如绘图软件)
- 系统需要解耦调用链(如消息队列)
- 避免滥用场景
- 简单请求直接调用(new Light().on())
- 对性能要求极高的场景(多一层封装损耗)
- 开源框架应用
- Java AWT的ActionEvent(命令模式变体)
- Spring JMS的MessageListener(解耦消息处理)
关键结论:命令模式的核心价值是“将请求封装为对象”,从而获得解耦、扩展性与事务控制能力。