命令模式(学习笔记2021.07.15)
前言:
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
**意图:**将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。 (解耦)
**主要解决:**在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
前提条件
设计一个家电自动化遥控器的API。
这个遥控器具有七个可编程的插槽(每个都可以指定到一个不同的家电装置),每个插槽都有对应的开关按钮。这个遥控器还具备一个整体的撤销按钮, 我也在光盘里附上一组Java类,
这些类是由多家厂商开发出来的,用来控制家电自动化装置,例如电灯、风扇、热水器、音响设备和其他类似的可控制装置。希望你能够创建一组控制遥控器的API,让每个插槽都能够控制一个或一组装置。
请注意,能够控制目前的装置和任何未来可能出现的装置,这一点是很重要的。
命令模式解决
命令模式的简单介绍
从餐厅来介绍:
从图上可以看出, 顾客的任务是将自己需要什么食品写到订单上,
而服务员也不关心顾客点的是什么, 找那个厨师, 只是将订单传递放在订单柜台, 然后通知来新订单了,
对应厨师根据订单内容, 开始制作食品, 并输出出来。
从而达到了顾客、厨师的解耦, 相互都不关注与不知道是谁来接任务。
使用命令模式解决遥控器
1.1 创建命令接口
(也就是餐厅的服务员)
/**
* @Author: ZhiHao
* @Date: 2021/7/14 17:34
* @Description: 命令基接口 (所有需要执行命令的实现该接口)
* @Versions 1.0
**/
public interface CommandBase {
/**
* 执行打开命令
*
* @author: ZhiHao
* @date: 2021/7/14
*/
void executeOpen();
/**
* 执行关闭命令
*
* @author: ZhiHao
* @date: 2021/7/14
*/
void executeStop();
}
1.2 创建电灯、风扇、命令实现
(真正执行命令的餐厅厨师是里面构建方法厂家提供的驱动对象-请求类)
/**
* @Author: ZhiHao
* @Date: 2021/7/14 17:42
* @Description: 风扇控制
* @Versions 1.0
**/
public class Blower implements CommandBase{
private String 厂家提供的对象;
public Blower(String 厂家提供的对象) {
this.厂家提供的对象 = 厂家提供的对象;
}
@Override
public void executeOpen() {
System.out.println(厂家提供的对象+"执行了打开命令动作");
}
@Override
public void executeStop() {
System.out.println(厂家提供的对象+"执行了打开命令动作");
}
}
// ---------------------电灯一样的代码--------------------------
1.3 创建遥控器
(也就是餐厅顾客调用者)
/**
* @Author: ZhiHao
* @Date: 2021/7/14 19:53
* @Description: 遥控器
* @Versions 1.0
**/
public class RemoteControl {
private final List<CommandBase> commandBase = new ArrayList<>();
/**
* 添加需要执行一系列宏命令
*
* @param commandBase
* @author: ZhiHao
* @date: 2021/7/14
*/
public void addCommandBase(CommandBase... commandBase) {
Optional.ofNullable(commandBase).map(Arrays::asList).ifPresent(this.commandBase::addAll);
}
public void addCommandOneBase(int index,CommandBase commandBase) {
Optional.ofNullable(commandBase).ifPresent(base-> this.commandBase.add(index,base));
}
/**
* 批量执行一系列宏命令
*
* @author: ZhiHao
* @date: 2021/7/14
*/
public void MacroCommandOpen(){
commandBase.forEach(CommandBase::executeOpen);
}
/**
* 执行单个命令
*
* @param index
* @author: ZhiHao
* @date: 2021/7/14
*/
public void open(int index){
commandBase.get(index).executeOpen();
}
public void MacroCommandStop(){
commandBase.forEach(CommandBase::executeOpen);
}
public void stop(int index){
commandBase.get(index).executeStop();
}
}
1.4 进行测试
@Test
public void applicationTest() throws Exception {
// 请求类
String electricLight = "电灯厂家提供的驱动对象";
String blower = "风扇厂家提供的驱动对象";
// 创建遥控器(顾客)
RemoteControl control = new RemoteControl();
// 创建命令 (订单), 电灯厂家提供的驱动对象才是真正执行请求的对象
CommandBase commandBase1 = new ElectricLight(electricLight);
CommandBase commandBase2 = new Blower(blower);
// 遥控器添加命令
control.addCommandOneBase(0,commandBase1);
control.addCommandOneBase(1,commandBase2);
// 执行打开命令, 会将命令传给调用者 (厨师)
control.open(0);
control.open(1);
control.stop(0);
}
// ----------------
电灯厂家提供的驱动对象执行了打开命令动作
风扇厂家提供的驱动对象执行了打开命令动作
电灯厂家提供的驱动对象执行了关闭命令动作
// 创建遥控器(顾客)
RemoteControl control = new RemoteControl();
// 创建命令, 电灯厂家提供的驱动对象才是真正执行请求的对象
CommandBase commandBase1 = new ElectricLight(electricLight);
CommandBase commandBase2 = new Blower(blower);
// 添加一系列宏命令
control.addCommandBase(commandBase1,commandBase2);
// 并执行
control.MacroCommandOpen();
定义:
命令模式将 “请求(命令)”封装成对象,以便使用不同的请求、 队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.
当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。
1