命令模式(Command Pattern)是一种行为型设计模式,它旨在将请求封装成对象,以便参数化其他对象,并支持请求的排队、记录请求日志、撤销操作等。
问题
假设有一个智能家居系统,其中有一个遥控器可以控制各种家电设备,比如电灯、电视等。现在要求遥控器能够支持以下功能:
- 可以控制多个不同品牌的电灯和电视。
- 遥控器可以记录所有操作的日志,方便用户查看。
- 用户可以按下撤销按钮来撤销上一次的操作。
在这个场景中,如果直接在遥控器中调用各种家电设备的方法,就会导致遥控器与具体的家电设备紧密耦合,一旦家电设备发生变化,可能需要修改遥控器的代码。
解决方案
使用命令模式,将每个操作封装成命令对象,遥控器只需要知道如何执行命令对象,而不需要知道具体的家电设备。这样就实现了请求发送者和请求接收者之间的解耦,同时也支持了请求的排队、延迟执行和撤销操作等高级功能
结构
-
命令(Command): 声明执行操作的接口,通常包含一个 execute() 方法。
-
具体命令(Concrete Command): 实现命令接口,具体命令对象通常会持有一个接收者对象,并调用接收者的方法来执行具体的操作。
-
接收者(Receiver): 知道如何执行一个请求,任何类都可能成为一个接收者,实际执行操作的类。
-
调用者(Invoker): 要求命令对象执行请求的对象,通常会持有一个命令对象,并在需要的时候调用命令对象的 execute() 方法。
-
客户端(Client): 创建具体命令对象并设置命令的接收者,以及设置调用者对象。
工作原理
- 命令对象封装请求: 将一个请求封装成一个对象,使得我们可以参数化其他对象。
- 调用者发送命令: 调用者对象持有命令对象,并在需要的时候调用命令对象的 execute() 方法。
- 具体命令执行操作: 具体命令对象会调用接收者的方法来执行具体的操作。
示例
下面是一个简单的命令模式的示例代码,实现了一个遥控器控制电灯开关的功能:
在这个实例中演示了如何使用命令模式实现一个遥控器控制电灯开关的功能。通过命令对象的封装,实现了请求发送者和请求接收者的解耦,同时也支持了撤销操作、重做操作等功能。
/**
* 命令接口
*/
public interface Command {
void execute();
}
/**
* 接收者类 - 电灯
*/
public class Light {
public void turnOn() {
System.out.println("Light is on");
}
public void turnOff() {
System.out.println("Light is off");
}
}
/**
* 具体命令类 - 关灯命令
*/
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
/**
* 具体命令类 - 开灯命令
*/
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
/**
* 调用者类 - 遥控器
*/
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
/**
* 客户端代码
*/
public class Client {
public static void main(String[] args) {
// 创建接收者对象
Light light = new Light();
// 创建具体命令对象
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
// 创建调用者对象
RemoteControl remoteControl = new RemoteControl();
// 设置命令对象并执行命令
remoteControl.setCommand(lightOnCommand);
remoteControl.executeCommand();
remoteControl.setCommand(lightOffCommand);
remoteControl.executeCommand();
}
}
优点
-
解耦调用者和接收者: 命令模式将调用者和接收者之间解耦,调用者无需知道接收者的具体类。
-
更好的扩展性: 可以很容易地增加新的命令类,而不需要修改调用者类。
-
支持撤销和重做操作: 命令对象可以保存请求的状态,从而实现撤销和重做操作。
缺点
-
增加了类的数量: 引入了额外的命令类,可能会增加系统的复杂性。
-
可能带来性能损失: 如果系统中有大量的命令类,可能会影响系统的性能。
应用场景
-
GUI操作: 如按钮的点击操作、菜单项的选择等。
-
事务控制: 如数据库事务的提交、回滚等。
-
日志记录: 可以使用命令模式记录系统的操作日志。