16,命令模式(Command)
16.1,问题引入_智能生活项目需求
- 假如有一套智能家电,照明灯、风扇、空调、冰箱、洗衣机等,需要在手机上安装APP进行控制
- 这些智能家电来自不同的厂家,每一个厂家针对设备都有不同的APP,但是我们不想下载那么多的APP,希望通过一个APP进行全控制,如万能遥控
- 要实现一个APP控制所有智能家电的需要,则各个智能家电需要一个统一的接口提供给APP使用,这时候可以考虑命令模式
- 命令模式可以将 动作的请求者 从 动作的执行者 对象中解耦出来
- 在这个例子中:动作的请求者是手机APP,动作的执行者就是各个智能家电
16.2,基本介绍
- 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道请求的操作是哪个,我们只需要在程序运行时指定具体的请求接收者即可。此时,可以使用命令模式设计
- 命令模式使得请求发送者和请求接收者消除彼此之间的耦合,让对象间的调用关系更加灵活,实现解耦
- 命令模式中,会将一个请求封装为一个对象,使用不同的参数来表示不同的请求,同时命令模式也支持撤销操作
- 用一个简单的解释:将军发送命令,士兵去执行。其中将军就是请求发送者,士兵是请求接收者,命令连接了将军和士兵
- 命令模式在
Spring
框架中的 JDBCTemplate
模块中有被使用,StatementCallBack
接口是命令顶层接口
16.3,类图
Light
:请求接收者,真正执行命令的角色,控制运行Command
:命令,也就是请求发送者和请求接收者的关联角色,知道如果实施和执行一个指令操作LightXXCommand
:具体命令角色,实现自 Command
,将一个命令与一个功能绑定,通过命令实现功能RemoteController
:请求发送者,即APP万能遥控,通过按钮实现功能控制。每一个命令角色封装,对万能遥控的呈现即为一个按钮Client
:客户端,即操作人,通过APP进行控制
16.4,代码实现
-
Light
:请求接收者,具体执行类
package com.self.designmode.command;
public class Light {public void on() {System.out.println("电灯打开了...");}public void off() {System.out.println("电灯关上了...");}}
-
Command
:顶层命令接口,连接请求发起者和请求接收者
package com.self.designmode.command;
public interface Command {void execute();void undo();}
-
LightOnCommand
:具体命令类,实际调度请求接收者的功能
package com.self.designmode.command;
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.on();}@Overridepublic void undo() {light.off();}
}
-
LightOffCommand
:具体命令类,实际调度请求接收者的功能
package com.self.designmode.command;
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.off();}@Overridepublic void undo() {light.on();}
}
-
NoCommand
:命令空实现,作为预留部分
package com.self.designmode.command;
public class NoCommand implements Command {@Overridepublic void execute() {System.out.println("do nothing,,,");}@Overridepublic void undo() {System.out.println("do nothing,,,");}}
-
RemoteController
:请求发起者,即万能遥控
package com.self.designmode.command;import java.util.HashMap;
import java.util.Map;
public class RemoteController {private Map<String, Command> onCommandMap &#61; new HashMap<>(16);private Map<String, Command> offCommandMap &#61; new HashMap<>(16);private Command undoCommand;public void setCommand(String type, Command onCommand, Command offCommand) {onCommandMap.put(type, onCommand);offCommandMap.put(type, offCommand);}public void onCommand(String type) {Command onCommand &#61; null &#61;&#61; onCommandMap.get(type) ? new NoCommand() : onCommandMap.get(type);onCommand.execute();undoCommand &#61; onCommand;}public void offCommand(String type) {Command offCommand &#61; null &#61;&#61; offCommandMap.get(type) ? new NoCommand() : offCommandMap.get(type);offCommand.execute();undoCommand &#61; offCommand;}public void undoCommand() {undoCommand.undo();}}
-
Client
&#xff1a;客户端&#xff0c;用户操作
package com.self.designmode.command;
public class Client {public static void main(String[] args) {Light light &#61; new Light();Command lightOnCommand &#61; new LightOnCommand(light);Command lightOffCommand &#61; new LightOffCommand(light);RemoteController remoteController &#61; new RemoteController();remoteController.setCommand("1", lightOnCommand, lightOffCommand);remoteController.onCommand("1");remoteController.offCommand("1");remoteController.undoCommand();}}
16.5&#xff0c;命令模式的注意事项和细节
- 将发起请求的对象和执行请求的对象解耦。发起请求的对象是调用者&#xff0c;调用者只需要调用命令对象的
execute()
方法可以让接口者工作&#xff0c;而不必知道接收者是谁、是如何工作的。命令对象会负责让对应的接收者执行工作。也就是说 请求发起者 和 请求接受者 是完全解耦的&#xff0c;命令对象在中间起连接作用 - 比较容易的设计一个命令队列。只需要将命令放入队列中&#xff0c;就可以进行多线程控制
- 比较容易的实现对请求的撤销和重做
- 空命令也是命令模式的一种设计&#xff0c;省去了判空操作&#xff0c;对命令进行了基础的空实现
- 命令模式的应用场景&#xff1a;界面的一个按钮都是一个命令&#xff0c;模拟基于命令的订单撤销、恢复、触发、反馈机制
- 命令模式不足&#xff1a;可能导致某些系统有过多的具体命令类&#xff0c;增加系统复杂性