定义
命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
解决什么问题
- 一个智能家电的遥控器,有很多按钮。
- 每个按钮对应一个家电的一个状态:(比如开关1对应开灯、开关2对应关灯、开关3对应将电风扇速度调到中档。。。),那么点一个按钮就可以将一个电器设置到相应的状态。
- 并且有一个撤销按钮,可以撤销上一次的操作。
- 家电类型可以会增加,按钮的功能可能会调整(例如开关1改为开启电冰箱)
如果不使用命令模式,有以下坏处:
- 按钮的功能每一次调整,会改动相当多的代码。
- 撤销功能很难实现(操作是各式各样的,有的是开灯,有的设置温度,有的关门,不具备统一的数据结构,怎么记录?)。
- 开关(请求的发起者)和家电(请求的执行者)强耦合。对于修改不关闭。
怎么解决
将每个命令都封装成对象,并且都实现同一接口,那么对于所有命令,提供给我们一种统一处理的可能。每个命令的具体实现,都包含一个撤销的方法,也就是命令自己维护自己的撤销方法,当需要撤销的时候,只需要调用命令的撤销方法就行了(并且不需要知道具体是什么命令,可以写在循环里)。
要点
- 重点在于要解耦“请求的发送者”和“请求的执行者”
- 请求被封装成了对象,所以可以添加到数组、队列等数据结构对于请求做统一处理
- 并且方便的支持请求的撤销操作
- 命令封装了接收者(执行者)和一个或一组动作
适用场景:
- 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。
- 命令需要进行各种管理逻辑。
- 需要支持撤消\重做操作。
- 命令的执行者各式各样,完全不同领域,但是还想对于命令进行统一的处理(比如要有所有的命令都输出一些信息,或者执行间距必须大于1秒)
- 记录系统的操作,持久化日志,死机或者crash后恢复现场
类图:
延伸
使用宏命令
核心就是原来的具体命令,不再执行单一的命令,而是包含一个命令数组,然后execute方法会循环执行command数组的execute方法。
核心代码
public class MacroCommand implements Command {
Command[] commands;
public MacroCommand(Command[] commands) {
this.commands = commands;
}
public void execute() {
for (int i = 0 ; i < commands.length ; i ++) {
commands[i].execute();
}
}
}