命令模式(Command Pattern)学习笔记
1. 模式定义
行为型设计模式,将请求封装为对象,使请求的发送者与接收者解耦。支持请求的排队、记录、撤销/重做等操作。
2. 适用场景
✅ 需要将操作参数化
✅ 需要支持事务操作(撤销/重做)
✅ 需要实现任务队列/线程池
✅ 需要记录操作历史
✅ 需要支持宏命令(命令组合)
3. 模式结构
4. 核心角色
角色 | 说明 |
---|---|
Command | 命令接口,声明执行操作的抽象方法 |
ConcreteCommand | 具体命令,绑定接收者与动作,实现execute()方法 |
Receiver | 接收者,实际执行操作的对象 |
Invoker | 调用者,触发命令执行 |
Client | 创建具体命令并设置接收者 |
5. 代码示例
5.1 智能家居控制示例
// 接收者 - 灯光设备
class Light {
public void on() {
System.out.println("打开灯光");
}
public void off() {
System.out.println("关闭灯光");
}
}
// 命令接口
interface Command {
void execute();
void undo();
}
// 具体命令
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
public void undo() {
light.off();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
public void undo() {
light.on();
}
}
// 调用者 - 遥控器
class RemoteControl {
private Command command;
private Command lastCommand;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
lastCommand = command;
}
public void pressUndo() {
if (lastCommand != null) {
lastCommand.undo();
lastCommand = null;
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Light livingRoomLight = new Light();
Command lightOn = new LightOnCommand(livingRoomLight);
Command lightOff = new LightOffCommand(livingRoomLight);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // 打开灯光
remote.setCommand(lightOff);
remote.pressButton(); // 关闭灯光
remote.pressUndo(); // 撤销操作(重新打开灯光)
}
}
6. 模式变种
- 宏命令(组合命令):
class MacroCommand implements Command {
private List<Command> commands = new ArrayList<>();
public void add(Command cmd) {
commands.add(cmd);
}
public void execute() {
for (Command cmd : commands) {
cmd.execute();
}
}
public void undo() {
for (int i = commands.size()-1; i >= 0; i--) {
commands.get(i).undo();
}
}
}
- 事务性命令:
class TransactionManager {
private Stack<Command> history = new Stack<>();
public void execute(Command cmd) {
cmd.execute();
history.push(cmd);
}
public void rollback() {
while (!history.isEmpty()) {
history.pop().undo();
}
}
}
7. 优缺点分析
✔️ 优点:
- 解耦请求发送者与接收者
- 支持撤销/重做操作
- 容易扩展新命令
- 支持命令的组合(宏命令)
- 支持请求排队与日志记录
❌ 缺点:
- 增加系统复杂度(每个操作都需要命令类)
- 可能产生大量具体命令类
- 需要管理命令的生命周期
8. 相关模式对比
模式 | 目的 | 关键区别 |
---|---|---|
策略模式 | 封装算法族 | 关注算法选择,通常不可逆 |
观察者模式 | 状态变化通知 | 事件驱动,被动通知 |
备忘录模式 | 状态保存与恢复 | 关注对象状态保存 |
责任链模式 | 请求传递处理 | 多个对象处理请求 |
9. 实际应用案例
- Java的Runnable接口(命令模式+线程池)
- Swing的Action接口
- 数据库事务管理
- 操作系统的任务调度
- 游戏开发中的输入处理
- 文本编辑器的撤销/重做功能
- Spring的JdbcTemplate(命令模式+模板方法)
10. 最佳实践建议
- 使用命令接口:保持命令的通用性
- 实现撤销机制:存储必要的状态信息
- 结合组合模式:实现宏命令功能
- 使用对象池:管理频繁创建的命令对象
- 添加日志功能:记录命令执行历史
- 支持异步执行:结合线程池实现
- 使用空对象模式:处理无操作命令(NullCommand)
11. 扩展应用(结合线程池)
// 命令接口(扩展支持异步)
interface AsyncCommand extends Command {
Future<?> executeAsync(ExecutorService executor);
}
// 具体命令实现
class FileBackupCommand implements AsyncCommand {
private String filePath;
public FileBackupCommand(String path) {
this.filePath = path;
}
public void execute() {
// 同步执行
backup();
}
public Future<?> executeAsync(ExecutorService executor) {
return executor.submit(this::backup);
}
private void backup() {
System.out.println("备份文件: " + filePath);
// 具体备份逻辑...
}
public void undo() {
System.out.println("恢复备份: " + filePath);
// 恢复逻辑...
}
}
// 使用示例
ExecutorService pool = Executors.newFixedThreadPool(2);
AsyncCommand cmd = new FileBackupCommand("data.db");
Future<?> task = cmd.executeAsync(pool);
🎮 设计原则体现:
- 单一职责原则:命令对象只负责执行特定操作
- 开闭原则:新增命令无需修改现有代码
- 依赖倒置原则:调用者依赖抽象命令接口
通过命令模式,可以实现灵活的操作管理机制,特别适合需要支持事务操作、任务队列、撤销/重做等功能的场景。该模式在GUI编程和事务处理系统中应用广泛,是解耦操作请求与具体实现的经典解决方案。