命令模式 (Command Pattern)
命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而使得可以用不同的请求对客户端进行参数化。命令模式允许请求的发送者和接收者解耦,使得发送者无需知道接收者的具体实现。
命令模式的核心思想是将请求封装成一个对象,这个对象包含了执行该请求所需的所有信息。它包括一个执行操作的方法,以及一组参数,用于配置和控制该方法的执行。通过封装请求为对象,我们可以灵活地传递和操作请求,而无需关心具体的实现细节。
在命令模式中,有以下几个关键角色:
-
命令(Command):它是命令模式的核心,定义了一个执行操作的接口,通常包含一个 execute() 方法。
-
具体命令(Concrete Command):它是命令接口的具体实现,封装了一个接收者(Receiver)的对象以及执行操作的具体逻辑。
-
接收者(Receiver):它是命令的实际执行者,包含了具体的业务逻辑。
-
调用者(Invoker):它负责调用命令对象执行请求。
-
客户端(Client):它创建具体的命令对象,并将命令对象传递给调用者进行请求的执行。
命令模式的优势如下:
-
解耦请求发送者和接收者:命令模式通过将请求封装为对象,使得请求的发送者和接收者解耦。发送者只需要知道如何调用命令对象,而无需关心具体的接收者和执行逻辑。
-
容易扩展和修改:由于命令模式将请求的具体实现封装在命令对象中,因此可以方便地添加新的命令类,而不需要修改调用者的代码。这样可以提高系统的灵活性和可维护性。
-
支持撤销和重做:命令模式可以记录请求的历史,从而支持撤销和重做操作。通过保存不同的命令对象,可以实现对命令的撤销、重做和回放。
命令模式适用于以下场景:
-
当需要将请求的发送者和接收者解耦时,可以考虑使用命令模式。例如,多个对象需要处理相同的请求,但是每个对象处理请求的方式不同,可以通过将请求封装成命令对象来实现。
-
当需要支持撤销、重做和回放操作时,可以使用命令模式。通过保存命令的历史记录,可以在需要时回溯执行命令,实现撤销和重做的功能。
-
当需要实现操作的参数化配置时,可以考虑使用命令模式。通过在命令对象中封装参数,可以在不同的场景下灵活地配置和执行命令。
总结起来,命令模式通过封装请求为对象,实现了请求发送者和接收者的解耦,提供了更灵活、可扩展和可维护的设计。它在需要解耦、支持撤销和重做、以及实现参数化配置的场景下非常有用。
举例说明
假设我们有一个家电控制系统,包含了电视(TV)和音响(Stereo)两个设备,以及相应的控制命令:打开电视、关闭电视、打开音响和关闭音响。
首先,我们定义一个命令接口 Command,其中包含了执行命令的方法 execute():
public interface Command {
void execute();
}
然后,我们实现具体的命令类,分别是打开电视命令 TVOnCommand、关闭电视命令 TVOffCommand、打开音响命令 StereoOnCommand 和关闭音响命令 StereoOffCommand:
public class TVOnCommand implements Command {
private TV tv;
public TVOnCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.turnOn();
}
}
public class TVOffCommand implements Command {
private TV tv;
public TVOffCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.turnOff();
}
}
public class StereoOnCommand implements Command {
private Stereo stereo;
public StereoOnCommand(Stereo stereo) {
this.stereo = stereo;
}
public void execute() {
stereo.turnOn();
}
}
public class StereoOffCommand implements Command {
private Stereo stereo;
public StereoOffCommand(Stereo stereo) {
this.stereo = stereo;
}
public void execute() {
stereo.turnOff();
}
}
接下来,我们定义电视和音响类,用于实际执行命令的操作:
public class TV {
public void turnOn() {
System.out.println("电视已打开");
}
public void turnOff() {
System.out.println("电视已关闭");
}
}
public class Stereo {
public void turnOn() {
System.out.println("音响已打开");
}
public void turnOff() {
System.out.println("音响已关闭");
}
}
最后,我们定义一个遥控器类 RemoteControl,它包含了一组命令按钮和相应的命令对象:
public class RemoteControl {
private Command onCommand;
private Command offCommand;
public void setOnCommand(Command onCommand) {
this.onCommand = onCommand;
}
public void setOffCommand(Command offCommand) {
this.offCommand = offCommand;
}
public void pressOnButton() {
onCommand.execute();
}
public void pressOffButton() {
offCommand.execute();
}
}
现在,我们可以在客户端代码中使用命令模式来控制电视和音响的操作:
public class Main {
public static void main(String[] args) {
TV tv = new TV();
Stereo stereo = new Stereo();
Command tvOnCommand = new TVOnCommand(tv);
Command tvOffCommand = new TVOffCommand(tv);
Command stereoOnCommand = new StereoOnCommand(stereo);
Command stereoOffCommand = new StereoOffCommand(stereo);
RemoteControl remoteControl = new RemoteControl();
remoteControl.setOnCommand(tvOnCommand);
remoteControl.setOffCommand(tvOffCommand);
remoteControl.pressOnButton(); // 打开电视
remoteControl.pressOffButton(); // 关闭电视
remoteControl.setOnCommand(stereoOnCommand);
remoteControl.setOffCommand(stereoOffCommand);
remoteControl.pressOnButton(); // 打开音响
remoteControl.pressOffButton(); // 关闭音响
}
}
运行上述代码,将会得到如下输出:
电视已打开
电视已关闭
音响已打开
音响已关闭
通过命令模式,我们将控制命令封装成具体的命令对象,通过调用者(遥控器)来执行命令。这样可以将请求的发送者和接收者解耦,使得命令的发送者不需要知道命令的具体执行细节。同时,命令模式也支持撤销和重做操作,可以方便地扩展和修改命令的行为。