定义:
命令模式是一种行为型设计模式,它将一个请求封装成一个对象,从而允许你参数化客户端对象 with different requests, queue or log requests, and support undoable operations.
解决什么问题:
- 将请求的发起者和执行者解耦。
- 将请求参数化,可以将不同的请求封装成不同的命令对象。
- 支持请求的排队执行、日志记录和撤销操作。
优点:
- 解耦请求和执行: 调用者不需要知道命令的具体实现,只需要知道如何发出命令即可。
- 扩展性强: 可以很容易地添加新的命令,而不需要修改已有的代码。
- 支持复杂操作: 可以将多个命令组合成一个复合命令,实现更复杂的操作。
- 支持撤销/重做: 可以记录命令的执行历史,实现撤销和重做功能。
缺点:
- 可能导致类爆炸: 如果命令很多,可能会导致创建大量的命令类。
- 增加代码复杂度: 相对于直接调用,使用命令模式会增加代码的复杂度。
使用时需要注意:
- 命令的粒度: 命令的粒度应该适中,不要太粗也不要太细。
- 命令的状态: 命令对象可能需要保存一些状态信息,例如命令的参数等。
- 命令的撤销: 如果需要支持撤销操作,需要在命令对象中实现撤销逻辑。
使用场景:
- GUI 应用程序中的菜单项、按钮等。
- 多线程环境中,将请求封装成命令对象,可以方便地进行异步处理。
- 实现事务机制,可以将多个操作封装成一个命令,保证所有操作要么全部成功,要么全部失败。
代码示例:
// 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();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
// Invoker: 调用者,持有命令对象,并调用命令对象的 execute() 方法
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
public class CommandPatternDemo {
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.pressButton();
remoteControl.setCommand(lightOffCommand);
remoteControl.pressButton();
}
}
输出:
Light is on
Light is off
在这个例子中,Light
是接收者,LightOnCommand
和 LightOffCommand
是具体命令类,RemoteControl
是调用者。
通过使用命令模式,我们可以将请求 (打开/关闭灯) 封装成对象,并将请求的发起者 (RemoteControl
) 和执行者 (Light
) 解耦。