命令模式是一种行为型设计模式,它将请求封装为对象,从而允许用户使用不同的请求、队列或日志请求来参数化其他对象,并支持可撤销的操作,这种模式的核心思想是将“发出请求的对象”与“接收并执行请求的对象”解耦,使得请求发送者无需知道接收者的具体实现细节,也无需知道请求是如何被处理的,命令模式在需要支持撤销、重做、延迟执行或记录操作日志等场景中非常有用。

命令模式的结构与UML表示
命令模式通常包含以下四个核心角色:
- 命令接口(Command):声明执行操作的接口,通常包含一个
execute()方法。 - 具体命令(ConcreteCommand):实现命令接口,持有一个接收者对象,并调用接收者的相应方法来执行操作。
- 调用者(Invoker):要求命令执行请求,通常会持有一个命令对象,并通过调用命令的
execute()方法来触发操作。 - 接收者(Receiver):知道如何执行与请求相关的操作,是真正处理请求的对象。
以下是命令模式的UML类图结构:
| 角色 | 类名 | 描述 |
|---|---|---|
| Command | Command |
接口,定义execute()方法 |
| ConcreteCommand | ConcreteCommand |
实现Command接口,关联Receiver |
| Receiver | Receiver |
执行具体操作的类 |
| Invoker | Invoker |
调用Command的execute()方法 |
命令模式的工作流程
- 客户端创建一个
ConcreteCommand对象,并指定其Receiver。 - 客户端将
ConcreteCommand对象传递给Invoker,并调用Invoker的设置方法(如setCommand())。 - Invoker在需要时调用
Command的execute()方法。 - ConcreteCommand的
execute()方法内部调用Receiver的相关方法来执行实际操作。
命令模式的代码示例
以下是一个简单的命令模式实现示例(以开灯操作为例):
// Receiver
class Light {
public void turnOn() {
System.out.println("Light is on");
}
public void turnOff() {
System.out.println("Light is off");
}
}
// Command
interface Command {
void execute();
}
// ConcreteCommand
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
// Invoker
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// Client
public class Main {
public static void main(String[] args) {
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // 输出: Light is on
}
}
命令模式的优缺点
优点:

- 解耦:调用者和接收者完全解耦,调用者无需知道接收者的具体实现。
- 扩展性:可以方便地添加新命令,无需修改现有代码。
- 支持撤销/重做:通过为命令对象添加
undo()方法,可以实现撤销操作。 - 支持日志和事务:可以将命令对象持久化,实现操作日志或事务功能。
缺点:
- 类数量增加:每个命令都需要一个具体命令类,可能导致系统类数量膨胀。
- 复杂性:对于简单操作,使用命令模式可能会增加不必要的复杂性。
相关问答FAQs
Q1: 命令模式与策略模式有什么区别?
A1: 命令模式关注的是将请求封装为对象,并通过调用者触发执行,强调的是“请求的发送与解耦”;而策略模式关注的是算法的封装和替换,强调的是“行为的灵活切换”,命令模式通常用于解耦调用者和接收者,而策略模式用于动态选择算法或行为。
Q2: 如何在命令模式中实现撤销操作?
A2: 可以在命令接口中添加一个undo()方法,具体命令类实现该方法以反向执行操作,对于开灯命令,undo()方法可以调用接收者的turnOff()方法,调用者(如RemoteControl)可以维护一个命令历史列表,通过调用undo()实现撤销功能。

