命令模式是一种行为设计模式,它将一个请求封装成一个对象,从而让你使用不同的请求、队列或者请求的日志来参数化其他对象。它也支持可撤销的操作。命令模式的关键是引入了抽象层------命令接口,具体命令实现该接口,执行操作的对象从执行具体操作的职责中解耦出来。
使用场景
- 当你需要参数化对象根据请求来执行操作时,可以使用命令模式,因为它可以指定和执行请求。
- 当你需要在不同的时间指定、排队和执行请求时。命令对象可以在一个队列中排队,并在稍后执行。
- 当需要支持撤销操作时。命令模式可以将状态回滚到某个命令被执行之前的状态。
- 当你需要将操作组装成复杂操作时,可以使用命令模式,它支持组合命令。
好处
- 降低耦合度:命令模式通过引入命令接口,使得请求的发送者和接收者解耦,增加新的命令很方便,不需要改动旧的代码。
- 增强可扩展性:可以很容易地添加新命令,只需实现接口即可。
- 支持撤销操作:可以通过实现撤销方法来轻松支持撤销。
- 可以组合命令:可以将多个命令组装成宏命令,一次性执行多个操作。
Java代码演示
接收者(Receiver)
接收者类Light
实际执行与请求相关的操作:
java
public class Light {
public void turnOn() {
System.out.println("Light is on");
}
public void turnOff() {
System.out.println("Light is off");
}
}
命令接口(Command)
命令接口定义了执行操作的方法:
java
public interface Command {
void execute();
}
具体命令(Concrete Commands)
具体命令实现命令接口,并定义接收者和操作之间的绑定关系:
java
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
调用者(Invoker)
调用者持有命令对象,并在某个时间点调用命令对象的execute()
方法:
java
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
if (command != null) {
command.execute();
}
}
}
客户端(Client)
客户端决定哪个命令执行,以及它的接收者是谁:
java
public class Client {
public static void main(String[] args) {
// 创建接收者
Light light = new Light();
// 创建命令,并设置其接收者
Command lightsOn = new LightOnCommand(light);
Command lightsOff = new LightOffCommand(light);
// 创建调用者,并关联命令
RemoteControl control = new RemoteControl();
control.setCommand(lightsOn); // 设置开灯命令
control.pressButton(); // 执行开灯命令
control.setCommand(lightsOff); // 设置关灯命令
control.pressButton(); // 执行关灯命令
}
}
命令模式的好处
通过这个更完整的示例,我们可以看到命令模式的几个关键好处:
- 解耦调用操作和接收者 :
RemoteControl
(调用者)不直接操作Light
(接收者),而是通过命令对象进行间接操作。这意味着Light
类的任何变化都不会直接影响到RemoteControl
类,反之亦然。 - 易于扩展 :要增加新的命令操作,只需添加一个新的
Command
实现即可,无需修改现有的Invoker
或Receiver
类。 - 组合命令:可以很容易地实现宏命令,即一个命令触发多个操作。
这样,使用命令模式提供了代码的灵活性和扩展性,同时也使得操作的撤销和重做成为可能。