命令模式(Command Pattern)是一种行为型设计模式,它的核心思想是将请求封装为独立的对象,使请求的发送者和接收者解耦,并支持请求的队列化、日志记录、撤销/重做等扩展功能。
一、命令模式的核心结构
1. 核心角色
- Command(命令接口):定义执行操作的接口(如
execute()
)
- ConcreteCommand(具体命令):实现命令接口,绑定接收者对象和动作
- Invoker(调用者):触发命令的对象(如按钮、菜单项)
- Receiver(接收者):真正执行操作的对象(如文件系统、数据库)
- Client(客户端):创建具体命令并设置其接收者
2. 简单代码示例
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
| interface Command { void execute(); }
class Light { public void turnOn() { System.out.println("灯已打开"); } public void turnOff() { System.out.println("灯已关闭"); } }
class LightOnCommand implements Command { private Light light; public LightOnCommand(Light light) { this.light = light; } @Override public void execute() { light.turnOn(); } }
class RemoteControlButton { private Command command; public void setCommand(Command command) { this.command = command; } public void press() { command.execute(); } }
public class Client { public static void main(String[] args) { Light light = new Light(); Command lightOn = new LightOnCommand(light); RemoteControlButton button = new RemoteControlButton(); button.setCommand(lightOn); button.press(); } }
|
二、命令模式的关键应用场景
需要解耦请求发送者和接收者
(如 GUI 按钮不应直接操作业务逻辑)
支持撤销/重做操作
(记录命令历史,反向执行命令)
实现操作队列或延迟执行
(如线程池任务调度)
支持事务操作
(一组命令要么全部成功,要么全部回滚)
三、宏命令(Macro Command)
1. 什么是宏命令?
宏命令是组合多个命令的复合命令,通过一次调用触发多个命令的执行,常用于:
- 批量操作(如「一键备份」触发文件压缩+上传+日志记录)
- 事务处理(多个操作作为一个原子操作)
2. 宏命令实现示例
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
| 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(); } } }
public class MacroClient { public static void main(String[] args) { Light light = new Light(); Speaker speaker = new Speaker(); Command lightOn = new LightOnCommand(light); Command speakerOn = new SpeakerOnCommand(speaker); MacroCommand morningRoutine = new MacroCommand(); morningRoutine.addCommand(lightOn); morningRoutine.addCommand(speakerOn); RemoteControlButton button = new RemoteControlButton(); button.setCommand(morningRoutine); button.press(); } }
|
四、命令模式 vs 其他模式
对比维度 |
命令模式 |
策略模式 |
核心目的 |
封装请求 |
封装算法 |
关注点 |
请求的触发与执行解耦 |
算法的灵活替换 |
典型应用 |
撤销/重做、事务 |
支付方式、排序策略 |
扩展方向 |
支持命令组合(宏命令) |
支持算法族的动态切换 |
五、命令模式的最佳实践
实现撤销操作
在命令接口中增加undo()
方法,保存执行前的状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| interface Command { void execute(); void undo(); }
class LightOnCommand implements Command { private Light light; private boolean prevState; public void execute() { prevState = light.isOn(); light.turnOn(); } public void undo() { if (!prevState) light.turnOff(); } }
|
结合责任链模式
实现命令的链式执行(一个命令执行后自动触发下一个命令)
与备忘录模式结合
实现更复杂的状态回滚机制
总结:命令模式的本质
通过将「做什么」(请求内容)与「谁来做」(执行对象)、「何时做」(触发时机)分离,实现了:
- 解耦:调用者无需知道接收者的存在
- 扩展性:轻松添加新命令
- 可编排性:通过宏命令实现复杂操作流
适用场景口诀:
当你有需要解耦的请求操作,
或想要支持撤销、重做,
或是批量操作要组合,
命令模式是你可靠的选择!