命令模式与宏命令的关系可以概括为「整体与部分」的组合关系,具体来说:
1. 层级关系
- 命令模式 是基础设计模式,提供单个命令的封装机制。
- 宏命令 是命令模式的扩展应用,通过组合多个命令形成复合命令,本质上是一个组合模式(Composite Pattern)与命令模式的结合。
2. 设计意图对比
|
命令模式 |
宏命令 |
核心目标 |
解耦请求发送者与执行者 |
批量处理多个命令 |
关注点 |
单个命令的生命周期管理 |
命令集合的编排与协同执行 |
典型应用 |
按钮点击操作、撤销/重做单个步骤 |
一键执行复杂操作流、事务处理 |
扩展性体现 |
支持不同的具体命令实现 |
支持动态增删子命令 |
3. 结构关系图解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ┌───────────────┐ │ Command │ │ (接口/抽象类) │ └──────┬────────┘ △ ┌───────┴───────┐ │ │ ┌─────────────────┐ ┌─────────────────┐ │ ConcreteCommand │ │ MacroCommand │ │ (具体单个命令) │ │ (复合命令容器) │ └─────────────────┘ └───────┬─────────┘ △ ┌───────┴───────┐ │ │ ┌─────────────┐ ┌─────────────┐ │ Command A │ │ Command B │ └─────────────┘ └─────────────┘
|
4. 关键协作方式
(1) 宏命令如何扩展命令模式
- 组合模式的应用:宏命令自身实现
Command
接口,同时内部维护一个Command
集合
- 透明性处理:对调用者而言,执行宏命令与执行普通命令无感知差异
- 递归执行:宏命令的
execute()
方法遍历调用所有子命令的execute()
(2) 典型交互流程
1 2 3 4 5 6
| [调用者] → 触发宏命令.execute() │ ▼ 宏命令遍历子命令集合 → 依次执行 command1.execute() command2.execute() command3.execute()
|
5. 实战案例:支持撤销的事务操作
场景需求
- 用户执行「批量删除文件」操作
- 需要支持整体撤销(回滚所有删除操作)
- 若任意子命令失败,自动回滚已执行的命令
代码实现要点
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| class TransactionMacroCommand implements Command { private List<Command> commands = new ArrayList<>(); private Stack<Command> executedCommands = new Stack<>();
public void addCommand(Command cmd) { commands.add(cmd); }
@Override public void execute() { executedCommands.clear(); try { for (Command cmd : commands) { cmd.execute(); executedCommands.push(cmd); } } catch (Exception e) { undoAll(); throw e; } }
public void undoAll() { while (!executedCommands.isEmpty()) { Command cmd = executedCommands.pop(); if (cmd instanceof UndoableCommand) { ((UndoableCommand) cmd).undo(); } } } }
interface UndoableCommand extends Command { void undo(); }
class DeleteFileCommand implements UndoableCommand { private File file; private boolean backupExists = false; public void execute() { if (file.exists()) { createBackup(); file.delete(); } } public void undo() { if (backupExists) restoreFromBackup(); } }
|
6. 二者的本质联系
- 相同基因:宏命令完全遵循命令模式的核心思想(将请求封装为对象)
- 能力增强:宏命令通过组合模式赋予了命令模式批量操作和嵌套执行的能力
- 设计演进:
单一命令
→ 可撤销命令
→ 宏命令
体现了设计模式的渐进式抽象过程
总结:选择使用宏命令的时机
当你的系统出现以下特征时,应考虑在命令模式基础上引入宏命令:
- 需要将多个关联操作原子化执行(如数据库事务)
- 存在重复操作序列需要抽象(如自动化脚本)
- 要求实现层级撤销(如 Photoshop 的批量操作回退)
- 需要动态组装操作流(如工作流引擎)