继续打卡设计模式
今天来聊一下的是命令模式
命令模式使得请求发送者与请求接受者消除彼此之间的耦合
一、实际问题
我们现在有一套只能家居,有照明灯、风扇、电视等等 我们现在需要在手机上安装一个app就可以控制这些家电的工作。
这些智能家电来自不同的厂家,我们不需要针对每一个家电都安装一个APP。分别控制。我们希望只要一个APP就可以控制全部智能家电。
针对这个问题我们先分析一下,我们肯定不会每一个家电都单独安装一个APP,那就是想用一个APP来控制这些所有家电,我们是不是需要对这个APP提供一个对外的接口来方便这些智能家电来调用呢。
二、命令模式来实现
直接用程序模拟可能更加直观,我们第一步就是需要有这些一个个智能家电个体
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class TVReceiver {
public void on() {
System.out.println(" 电视机打开了.. ");
}
public void off() {
System.out.println(" 电视机关闭了.. ");
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class LightReceiver {
public void on() {
System.out.println(" 电灯打开了.. ");
}
public void off() {
System.out.println(" 电灯关闭了.. ");
}
}
现在两套智能家电也已经具备了我们需要的就是针对这两套智能家电来进行便捷的控制,手机APP就好比是我们的客户端,最后测试我们就是针对客户端来调用这些智能家电。
那现在我们就需要来提供一个统一的接口了
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
//创建命令接口
public interface Command {
//执行
public void execute();
//撤销
public void undo();
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class TVOffCommand implements Command {
// 聚合TVReceiver
TVReceiver tv;
// 构造器
public TVOffCommand(TVReceiver tv) {
super();
this.tv = tv;
}
@Override
public void execute() {
// 调用接收者的方法
tv.off();
}
@Override
public void undo() {
// 调用接收者的方法
tv.on();
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class TVOnCommand implements Command {
// 聚合TVReceiver
TVReceiver tv;
// 构造器
public TVOnCommand(TVReceiver tv) {
super();
this.tv = tv;
}
@Override
public void execute() {
// 调用接收者的方法
tv.on();
}
@Override
public void undo() {
// 调用接收者的方法
tv.off();
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class LightOffCommand implements Command {
// 聚合LightReceiver
LightReceiver light;
// 构造器
public LightOffCommand(LightReceiver light) {
super();
this.light = light;
}
@Override
public void execute() {
// 调用接收者的方法
light.off();
}
@Override
public void undo() {
// 调用接收者的方法
light.on();
}
}
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class LightOnCommand implements Command {
LightReceiver light;
public LightOnCommand(LightReceiver light) {
super();
this.light = light;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
}
/**
* @author: 德鑫
* Description:
* 没有任何处理 空执行。用于初始化每一个按钮。当调用空命令时对象什么都不做
* @Date: 2021/01/27
*/
public class NoCommand implements Command{
@Override
public void execute() {
}
@Override
public void undo() {
}
}
好的现在我们有一个控制层。我们假象现在手里是一个开关,那么我们则根据输入的参数来确定我们到的是对那一个家电是开还是关
/**
* @author: 德鑫
* Description:
* @Date: 2021/01/27
*/
public class RemoteController {
Command[] onCommands;
Command[] offCommands;
Command undoCommand;
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for (int i = 0; i < 5; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
// 给我们的按钮设置你需要的命令
public void setCommand(int no, Command onCommand, Command offCommand) {
onCommands[no] = onCommand;
offCommands[no] = offCommand;
}
//按下开按钮
public void onButtonWasPushed(int no){
// 找到你按下的开的按钮, 并调用对应方法
onCommands[no].execute();
// 记录这次的操作,用于撤销
undoCommand = onCommands[no];
}
// 按下开按钮
public void offButtonWasPushed(int no) { // no 0
// 找到你按下的关的按钮, 并调用对应方法
offCommands[no].execute();
// 记录这次的操作,用于撤销
undoCommand = offCommands[no];
}
// 按下撤销按钮
public void undoButtonWasPushed() {
undoCommand.undo();
}
}
最后写一个客户端来进行测试
这个客户端测试就是根据传入不同的类型。来调用不同的方法进行处理。这里也可以将接口替换成抽象类的形式
public class Client {
public static void main(String[] args) {
LightReceiver lightReceiver = new LightReceiver();
//创建电灯相关的开关命令
LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
//遥控器
RemoteController remoteController = new RemoteController();
//给我们的遥控器设置命令, 比如 no = 0 是电灯的开和关的操作
remoteController.setCommand(0, lightOnCommand, lightOffCommand);
System.out.println("--------按下灯的开按钮-----------");
remoteController.onButtonWasPushed(0);
System.out.println("--------按下灯的关按钮-----------");
remoteController.offButtonWasPushed(0);
System.out.println("--------按下撤销按钮-----------");
remoteController.undoButtonWasPushed();
System.out.println("=========使用遥控器操作电视机==========");
TVReceiver tvReceiver = new TVReceiver();
TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
//给我们的遥控器设置命令, 比如 no = 1 是电视机的开和关的操作
remoteController.setCommand(1, tvOnCommand, tvOffCommand);
System.out.println("--------按下电视机的开按钮-----------");
remoteController.onButtonWasPushed(1);
System.out.println("--------按下电视机的关按钮-----------");
remoteController.offButtonWasPushed(1);
System.out.println("--------按下撤销按钮-----------");
remoteController.undoButtonWasPushed();
}
}
三、命令模式的总结
- 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收 者是谁,也不知道被请求的操作是哪个, 我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计 。
- 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
- 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式 也支持可撤销的操作。