命令模式
什么是命令模式
命令模式(Command Pattern)是一种行为设计模式,它将请求封装为对象,从而使你可用不同的请求把客户端与请求的处理者解耦,也称动作模式或事物模式。
在命令模式中,命令对象封装了接收者对象的动作,调用者通过调用命令对象来执行该动作,而无需知道具体的接收者对象是谁。
命令模式的主要角色包括:
- 命令接口(Command): 声明一个执行操作的接口。
- 具体命令(ConcreteCommand): 实现命令接口,将接收者对象绑定于一个动作,调用接收者对象的相应操作,以实现execute()方法。
- 请求者(Invoker): 要求命令执行一个请求。
- 接收者(Receiver): 知道如何执行与请求相关联的操作的类。
- 客户端(Client): 创建一个具体命令对象,并设置其接收者。
优点:
- 解耦请求者和接收者: 在命令模式中,请求者不直接与接收者交互,而是通过命令对象进行中介,这彻底消除了请求者与接收者之间的耦合。这种解耦使得请求者和接收者可以独立变化,提高了系统的灵活性和可维护性。
- 支持撤销和重做: 由于命令对象封装了操作,因此可以很容易地实现对请求的撤销和重做功能。这对于需要支持用户撤销操作或实现事务回滚的系统来说非常有用。
- 可记录日志和监控: 命令对象可以被保存到持久化的媒介中,用于记录操作日志或进行监控。这对于审计、追踪和调试等操作非常有帮助。
- 易于扩展和组合: 新的命令可以很容易地添加到系统中,而不影响现有的代码。此外,命令对象还可以组合起来形成更复杂的操作序列。
缺点:
- 可能导致过多的具体命令类: 对于每个请求接收者的调用操作,都需要设计一个具体命令类。在某些系统中,如果请求接收者的操作种类繁多,那么可能会导致系统中存在大量的具体命令类,这会增加系统的复杂性。
- 可能增加系统开销: 由于每个请求都需要通过命令对象进行中介,因此相对于直接调用接收者对象的方法,命令模式可能会增加一些额外的系统开销。
常见运用场景包括:
- GUI设计中的按钮点击事件: 在图形用户界面设计中,按钮的点击事件可以通过命令模式进行处理。每个按钮的点击事件可以关联一个命令对象,当按钮被点击时,执行相应的命令。
- 撤销/重做操作: 在需要支持撤销和重做功能的系统中,命令模式可以很好地实现这一需求。通过保存每次操作的命令对象,可以在需要时执行撤销或重做操作。
- 事务处理: 在需要确保一系列操作要么全部成功要么全部失败(即原子性)的系统中,可以使用命令模式来封装这些操作,并在一个命令对象中执行它们。如果某个操作失败,可以回滚整个命令对象,确保数据的一致性。
- 日志记录: 对于那些需要记录用户操作日志的系统,命令模式可以将每个操作封装为一个命令对象,并将其保存到日志中,以便后续查看和分析。
案例
通过命令模式实现电灯的开/关
UML
实现步骤:
- 创建命令的具体执行者Light,定义电灯的具体执行开关的方法
- 创建命令接口,定义执行的抽象方法
- 创建具体命令接口的实现,通过持有具体执行的引用,执行指定命令
- 创建请求者,用于发出指令,处理请求指令
实现代码
Light.java
// 命令的接收者
public class Light {
public void on() {
System.out.println("Light is on");
}
public void off() {
System.out.println("Light is off");
}
}
Command.java
// 命令接口
public interface Command {
// 执行动作
void execute();
}
LightOnCommand.java
// 命令接口的具体实现
public class LightOnCommand implements Command{
// 持有命令接受者的引用
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
LightOffCommand.java
// 命令接口的具体实现
public class LightOffCommand implements Command{
// 持有命令接受者的引用
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
SimpleRemoteControl.java
// 请求者:持有命令接口的实现,用于处理命令请求
public class SimpleRemoteControl {
// 持有命令接口的实现
private Command command;
public void setCommand(Command command) {
this.command = command;
}
// 执行动作
public void excute(){
command.execute();
}
}
执行结果: