命令模式(Command Pattern)
命令模式(Command Pattern)是一种行为设计模式,它将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,队列或记录请求日志,以及支持可撤销的操作。在命令模式中,请求被封装为一个对象,这个对象包含了执行请求的方法,以及所有必要的参数。这样,客户端只需创建并传递一个命令对象给调用者,而无需关心具体的实现细节。
核心组件
- Command(命令):定义了执行请求的接口。
- ConcreteCommand(具体命令):实现了命令接口,负责调用请求的接收者来执行请求。
- Receiver(接收者):知道如何实施与执行一个请求相关的操作。
- Invoker(调用者):要求命令执行请求的对象。
- Client(客户端):创建具体命令对象并设置其接收者。
适用场景
- 需要将请求发送者和请求接收者解耦:
- 命令模式允许请求发送者和接收者独立变化,互不影响。
- 需要支持命令的排队、记录请求日志、撤销操作等功能:
- 命令模式可以轻松地扩展这些功能。
- 需要将一组操作组合在一起形成一个命令:
- 命令模式可以将多个操作封装成一个命令对象。
实现实例
基于命令模式(Command Pattern)的遥控器控制家电的系统。
命令接口(Command Interface)
定义了执行命令的方法。
public interface Command {
void execute(); // 执行命令的方法
}
具体命令(Concrete Command)
实现了命令接口,负责调用接收者执行具体操作。
LightOnCommand
public class LightOnCommand implements Command {
private Light light; // 接收者对象
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn(); // 调用接收者的方法
}
}
LightOffCommand
public class LightOffCommand implements Command {
private Light light; // 接收者对象
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOff(); // 调用接收者的方法
}
}
接收者(Receiver)
知道如何实施与执行请求相关的操作。
public class Light {
public void turnOn() {
System.out.println("Light is on"); // 执行打开灯的操作
}
public void turnOff() {
System.out.println("Light is off"); // 执行关闭灯的操作
}
}
调用者(Invoker)
要求命令执行请求的对象。
public class RemoteControl {
private Command command; // 当前命令对象
public void setCommand(Command command) {
this.command = command; // 设置命令对象
}
public void pressButton() {
command.execute(); // 执行当前命令
}
}
客户端代码(Client Code)
演示如何使用命令模式。
public class Client {
public static void main(String[] args) {
Light livingRoomLight = new Light(); // 创建接收者对象
Command lightOn = new LightOnCommand(livingRoomLight); // 创建打开灯的命令
Command lightOff = new LightOffCommand(livingRoomLight); // 创建关闭灯的命令
RemoteControl remoteControl = new RemoteControl(); // 创建调用者对象
remoteControl.setCommand(lightOn); // 设置打开灯的命令
remoteControl.pressButton(); // 执行打开灯的命令
remoteControl.setCommand(lightOff); // 设置关闭灯的命令
remoteControl.pressButton(); // 执行关闭灯的命令
}
}
解释
- 命令接口(Command Interface):定义了
execute()
方法,所有具体命令类都必须实现这个方法。 - 具体命令(Concrete Command):实现
Command
接口,负责调用接收者对象的具体操作。LightOnCommand
和LightOffCommand
分别负责打开和关闭灯光。 - 接收者(Receiver):
Light
类知道如何执行具体操作,如打开和关闭灯光。 - 调用者(Invoker):
RemoteControl
类持有一个命令对象,通过setCommand()
方法设置当前命令,并通过pressButton()
方法执行命令。 - 客户端代码(Client Code):客户端代码创建具体的接收者、命令和调用者对象,并通过设置和执行命令来控制灯光的开关。
这种设计模式的优势在于将请求的发送者和接收者解耦,使得系统更灵活,可以在不修改调用者代码的情况下新增或更改命令。
优缺点
优点
- 降低发送者和接收者之间的耦合:
- 发送者只需要知道如何发送命令,而不需要了解接收者的具体实现。
- 容易扩展新命令:
- 可以很容易地增加新的具体命令类。
- 支持撤销和重做操作:
- 可以通过保存历史命令实现撤销和重做功能。
缺点
- 可能会导致过多的具体命令类:
- 如果系统中命令较多,可能会导致类的数量增加。
类图
+----------------+ +------------------+
| Command |-------->| ConcreteCommand|
+----------------+ +------------------+
| + execute() | | + execute() |
+----------------+ +------------------+
| | |
+----------------+ |
|
+-------------------+--------+----------------+
| | | |
+---------------+ +-----------------+ +----------------+ +--------------+
| Receiver | | LightOnCommand | | LightOffCommand| | ... |
+---------------+ +-----------------+ +----------------+ +--------------+
| + action() | | + execute() | | + execute() | | + execute() |
+---------------+ +-----------------+ +----------------+ +--------------+
总结
命令模式允许将请求封装成对象,使得请求的发送者和接收者解耦,并支持撤销、重做等操作。通过命令模式,可以轻松扩展新的命令,支持排队、记录日志等功能,是一种非常有用的设计模式。