什么是命令模式?
命令模式是一种行为型设计模式,核心是将每种请求或操作封装为一个独立的对象,从而可以集中管理这些请求或操作,比如将请求队列化依次执行、或者对操作进行记录和撤销。
命令模式通过将请求的发送者(客户端)和接收者(执行请求的对象)解耦,提供了更大的灵活性和可维护性。
听不懂上面这句话很正常,我来举个例子。
我们在生活中都用过电视机,我们 就相当于客户端,要操作电视来换台;而 电视 就是执行请求的对象,要根据我们的操作来换台。但是我们一般不会直接按电视上的按钮来换台,而是用一个 遥控器,通过点击遥控器上的 操作按钮 来控制电视。
这样就相当于把我们和电视解耦了。哪怕遥控器丢了,再换一个遥控器就好了;而且现在手机都能作为万能的电视遥控器,我们可以同时遥控多个品牌的设备,不用关心设备的具体品牌型号,提供了更大的方便。
命令模式的优点和应用场景
正如上面的例子,命令模式最大的优点就是解耦请求发送者和接受者,让系统更加灵活、可扩展。
由于每个操作都是一个独立的命令类,所以我们需要新增命令操作时,不需要改动现有代码。
命令模式典型的应用场景:
系统需要统一处理多种复杂的操作,比如操作排队、记录操作历史、撤销重做等。
系统需要持续增加新的命令、或者要处理复杂的组合命令(子命令),使用命令模式可以实现解耦。
命令模式的要素和实现
通过上面用户使用遥控器来操作电视机设备的例子,带大家理解命令模式的关键要素和实现代码。
1)命令
相当于遥控器操作按钮的制作规范
命令是一个抽象类或接口,它定义了执行操作的方法,通常是 execute,该方法封装了具体的操作。
代码如下:
public interface Command { void execute(); }
2)具体命令
相当于遥控器的某个操作按钮
具体命令是命令接口的具体实现类,它负责将请求传递给接收者(设备)并执行具体的操作。
比如定义一个关闭设备命令,代码如下:
public class TurnOffCommand implements Command { private Device device; public TurnOffCommand(Device device) { this.device = device; } public void execute() { device.turnOff(); } }
还可以定义开启设备命令,代码如下:
public class TurnOnCommand implements Command { private Device device; public TurnOnCommand(Device device) { this.device = device; } public void execute() { device.turnOn(); } }
3)接受者
相当于被遥控的设备
接收者是最终执行命令的对象,知道如何执行具体的操作。
比如定义一个设备类,代码如下:
public class Device { private String name; public Device(String name) { this.name = name; } public void turnOn() { System.out.println(name + " 设备打开"); } public void turnOff() { System.out.println(name + " 设备关闭"); } }
4)调用者
相当于遥控器
作用是接受客户端的命令并执行。
比如定义遥控器类,代码如下:
public class RemoteControl { private Command command; public void setCommand(Command command) { this.command = command; } public void pressButton() { command.execute(); } }
以上只是最基础的调用者类,还可以给遥控器类增加更多能力,比如存储历史记录、撤销重做等。
5)客户端
相当于使用遥控器的人
客户端的作用是创建命令对象并将其与接收者关联(绑定设备),然后将命令对象传递给调用者(按遥控器),从而触发执行。
示例客户端代码如下:
public class Client { public static void main(String[] args) { // 创建接收者对象 Device tv = new Device("TV"); Device stereo = new Device("Stereo"); // 创建具体命令对象,可以绑定不同设备 TurnOnCommand turnOn = new TurnOnCommand(tv); TurnOffCommand turnOff = new TurnOffCommand(stereo); // 创建调用者 RemoteControl remote = new RemoteControl(); // 执行命令 remote.setCommand(turnOn); remote.pressButton(); remote.setCommand(turnOff); remote.pressButton(); } }
在这个示例中,命令模式将遥控器按钮的按下操作与实际设备的开关操作解耦,从而实现了灵活的控制和可扩展性。
整个程序的 UML 类图如下:
命令模式是一种行为型设计模式,核心是将每种请求或操作封装为一个独立的对象,从而可以集中管理这些请求或操作,比如将请求队列化依次执行、或者对操作进行记录和撤销。
命令模式通过将请求的发送者(客户端)和接收者(执行请求的对象)解耦,提供了更大的灵活性和可维护性。
听不懂上面这句话很正常,我来举个例子。
我们在生活中都用过电视机,我们 就相当于客户端,要操作电视来换台;而 电视 就是执行请求的对象,要根据我们的操作来换台。但是我们一般不会直接按电视上的按钮来换台,而是用一个 遥控器,通过点击遥控器上的 操作按钮 来控制电视。
这样就相当于把我们和电视解耦了。哪怕遥控器丢了,再换一个遥控器就好了;而且现在手机都能作为万能的电视遥控器,我们可以同时遥控多个品牌的设备,不用关心设备的具体品牌型号,提供了更大的方便。
命令模式的优点和应用场景
正如上面的例子,命令模式最大的优点就是解耦请求发送者和接受者,让系统更加灵活、可扩展。
由于每个操作都是一个独立的命令类,所以我们需要新增命令操作时,不需要改动现有代码。
命令模式典型的应用场景:
系统需要统一处理多种复杂的操作,比如操作排队、记录操作历史、撤销重做等。
系统需要持续增加新的命令、或者要处理复杂的组合命令(子命令),使用命令模式可以实现解耦。
命令模式的要素和实现
通过上面用户使用遥控器来操作电视机设备的例子,带大家理解命令模式的关键要素和实现代码。
1)命令
相当于遥控器操作按钮的制作规范
命令是一个抽象类或接口,它定义了执行操作的方法,通常是 execute,该方法封装了具体的操作。
代码如下:
public interface Command { void execute(); }
2)具体命令
相当于遥控器的某个操作按钮
具体命令是命令接口的具体实现类,它负责将请求传递给接收者(设备)并执行具体的操作。
比如定义一个关闭设备命令,代码如下:
public class TurnOffCommand implements Command { private Device device; public TurnOffCommand(Device device) { this.device = device; } public void execute() { device.turnOff(); } }
还可以定义开启设备命令,代码如下:
public class TurnOnCommand implements Command { private Device device; public TurnOnCommand(Device device) { this.device = device; } public void execute() { device.turnOn(); } }
3)接受者
相当于被遥控的设备
接收者是最终执行命令的对象,知道如何执行具体的操作。
比如定义一个设备类,代码如下:
public class Device { private String name; public Device(String name) { this.name = name; } public void turnOn() { System.out.println(name + " 设备打开"); } public void turnOff() { System.out.println(name + " 设备关闭"); } }
4)调用者
相当于遥控器
作用是接受客户端的命令并执行。
比如定义遥控器类,代码如下:
public class RemoteControl { private Command command; public void setCommand(Command command) { this.command = command; } public void pressButton() { command.execute(); } }
以上只是最基础的调用者类,还可以给遥控器类增加更多能力,比如存储历史记录、撤销重做等。
5)客户端
相当于使用遥控器的人
客户端的作用是创建命令对象并将其与接收者关联(绑定设备),然后将命令对象传递给调用者(按遥控器),从而触发执行。
示例客户端代码如下:
public class Client { public static void main(String[] args) { // 创建接收者对象 Device tv = new Device("TV"); Device stereo = new Device("Stereo"); // 创建具体命令对象,可以绑定不同设备 TurnOnCommand turnOn = new TurnOnCommand(tv); TurnOffCommand turnOff = new TurnOffCommand(stereo); // 创建调用者 RemoteControl remote = new RemoteControl(); // 执行命令 remote.setCommand(turnOn); remote.pressButton(); remote.setCommand(turnOff); remote.pressButton(); } }
在这个示例中,命令模式将遥控器按钮的按下操作与实际设备的开关操作解耦,从而实现了灵活的控制和可扩展性。
整个程序的 UML 类图如下: