命令模式(Command Pattern)
命令模式是一种行为型设计模式,它将「请求」封装为对象,从而实现请求发送者(Invoker)与请求接收者(Receiver)的完全解耦,并支持撤销、重做、排队、日志记录等扩展能力。
一、命令模式的核心概念
命令模式的核心思想是:将请求抽象成独立的命令对象,使得请求可以被存储、传递、排队、撤销或组合。
主要角色包括:
| 角色 | 职责 |
|---|---|
| Command(命令接口) | 声明执行操作的接口 |
| ConcreteCommand(具体命令) | 实现命令接口,绑定接收者并调用其方法 |
| Receiver(接收者) | 真正执行命令的对象 |
| Invoker(调用者) | 持有命令对象并触发执行 |
| Client(客户端) | 创建命令对象并设置接收者 |
二、命令模式解决的问题
命令模式主要解决:
- 请求者与执行者之间的紧耦合(例如 GUI 按钮与业务逻辑)。
- 需要支持撤销/重做、事务、日志记录等场景。
- 需要将操作排队、组合成宏命令或延迟执行。
三、适用场景
命令模式适用于:
- GUI 中按钮、菜单项触发的操作。
- 需要撤销/重做的编辑器、IDE、绘图软件。
- 事务系统、操作日志回放。
- 遥控器控制家电、游戏指令、机器人指令等。
四、命令模式的优缺点
✅ 优点
- 完全解耦调用者与接收者。
- 易扩展:新增命令无需修改现有代码。
- 支持撤销/重做、事务、日志、队列等高级功能。
❌ 缺点
- 命令类数量可能过多,导致系统复杂度上升。
- 间接调用带来一定性能开销。
五、命令模式结构图(文字版)
Client → 创建命令对象并设置接收者
Invoker → 持有命令对象并触发执行
Command → 抽象命令接口
ConcreteCommand → 实现命令并调用 Receiver
Receiver → 执行实际操作
六、典型代码示例(简化版)
1. 命令接口
java
public interface Command {
void execute();
}
2. 接收者
java
public class Receiver {
public void action() {
System.out.println("执行具体操作");
}
}
3. 具体命令
java
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
4. 调用者
java
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
5. 客户端
java
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand();
七、时序图
接收者 Receiver 具体命令 ConcreteCommand 调用者 Invoker 客户端 Client 接收者 Receiver 具体命令 ConcreteCommand 调用者 Invoker 客户端 Client #mermaid-svg-9P7nYhK6TKwR4ZVL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9P7nYhK6TKwR4ZVL .error-icon{fill:#552222;}#mermaid-svg-9P7nYhK6TKwR4ZVL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9P7nYhK6TKwR4ZVL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9P7nYhK6TKwR4ZVL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9P7nYhK6TKwR4ZVL .marker.cross{stroke:#333333;}#mermaid-svg-9P7nYhK6TKwR4ZVL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9P7nYhK6TKwR4ZVL p{margin:0;}#mermaid-svg-9P7nYhK6TKwR4ZVL .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9P7nYhK6TKwR4ZVL text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-9P7nYhK6TKwR4ZVL .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-9P7nYhK6TKwR4ZVL .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-9P7nYhK6TKwR4ZVL #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-9P7nYhK6TKwR4ZVL .sequenceNumber{fill:white;}#mermaid-svg-9P7nYhK6TKwR4ZVL #sequencenumber{fill:#333;}#mermaid-svg-9P7nYhK6TKwR4ZVL #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-9P7nYhK6TKwR4ZVL .messageText{fill:#333;stroke:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9P7nYhK6TKwR4ZVL .labelText,#mermaid-svg-9P7nYhK6TKwR4ZVL .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .loopText,#mermaid-svg-9P7nYhK6TKwR4ZVL .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-9P7nYhK6TKwR4ZVL .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-9P7nYhK6TKwR4ZVL .noteText,#mermaid-svg-9P7nYhK6TKwR4ZVL .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-9P7nYhK6TKwR4ZVL .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9P7nYhK6TKwR4ZVL .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9P7nYhK6TKwR4ZVL .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9P7nYhK6TKwR4ZVL .actorPopupMenu{position:absolute;}#mermaid-svg-9P7nYhK6TKwR4ZVL .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-9P7nYhK6TKwR4ZVL .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9P7nYhK6TKwR4ZVL .actor-man circle,#mermaid-svg-9P7nYhK6TKwR4ZVL line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-9P7nYhK6TKwR4ZVL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建接收者 new Receiver()1创建命令 new ConcreteCommand(receiver)2创建调用者 new Invoker()3setCommand(command)4executeCommand()5execute()6action()7
八、总结
命令模式通过将请求封装为对象,实现了请求发送者与执行者的彻底解耦,并天然支持撤销、重做、事务、日志等高级功能,是行为型设计模式中非常重要的一种。