一、命令模式简介
1. 什么是命令模式
命令模式(Command Pattern) 属于行为性设计模式的一种,在<设计模式之禅>一书中其定义为: Encapsulate a request as an object ,thereby letting you parameterize clients with different request , queue or log requests ,and support undoable operations(将一个请求封装成一个对象,从而让你使用不同的请求将客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能)。简单来讲命令模式就是将命令以对象的形式传递给业务方,业务方负责寻找处理该命令的对象并将命令传递给相应的对象,执行对象命令。
2. 简单说明
同学们单纯的去看理论概念来理解设计模式肯定是有一点点的难度,所以我们还是将设计模式套入我们日常生活中的一些现实映射来通过一个小小的例子来帮助我们理解。
不知道同学们平时有没有使用过AI助手,例如小爱同学,天猫精灵,siri等等。作为一个拥抱物联生活的fashion男孩(主要是懒),AI物联助手为我的生活提供了极大的便利。这里简单的说明下什么是物联AI助手:
物联AI助手简单的来讲就是一种可以通过语音或APP控制的遥控器,它可以分析你对他下达的指令来完成对智能家居的控制。比如你对着手机说小爱同学,帮我关一下卧室灯。那么此时小爱同学就会分析你的命令并且将命令发送给卧室的智能灯泡,智能灯泡接收到命令就会关闭。
那么针对这个业务场景,我们先简单的分析一下业务模型及参与角色:
- 命令发送方(Client): 首先我们肯定是需要一个命令的产生者,在这个业务场景里,我对小爱同学发送一个关灯指令,那么命令的产生者就是我,而在正常的产品模型中,这个命令的产生者往往是客户端。
- 命令执行者(Invoker): 负责接受业务端发送的所有命令,并且分析命令,将命令委托给对应的业务模块进行处理。
- 命令(command):命令就很好理解了,简单的来说就是我们下达的指令。
- 命令接受者(Recevier):负责执行client下达的指令,负责具体业务逻辑的实现。
那么根据我们的分析,我们来画一个智能AI控制灯泡开关的业务图:
接下来我们要做的就是一个简单的代码实现。
3. 代码实现
第一步: 创建命令接受者抽象类及实现类
// 抽象类
public abstract class BulbRecevier {
// 开灯
public abstract void open();
// 关灯
public abstract void close();
}
// 实现类
public class BedRoomBulbRecevier extends BulbRecevier {
@Override
public void open() {
System.out.println("卧室灯打开了");
}
@Override
public void close() {
System.out.println("卧室灯关闭了");
}
}
第二步: 创建命令接口及命令实现类
// 接口
public interface Command {
void execute();
}
// 实现类
public class CloseBulbCommand implements Command {
private BulbRecevier bulbRecevier;
public CloseBulbCommand(BulbRecevier bulbRecevier) {
super();
this.bulbRecevier = bulbRecevier;
}
@Override
public void execute() {
bulbRecevier.close();
}
}
第三步: 创建命令执行类 Invoker
// 抽象类
public abstract class AIInvoker {
public abstract void action(Command command);
}
// 实现类
public class XiaoAIInvoker extends AIInvoker {
@Override
public void action(Command command) {
command.execute();
}
}
第四步: 创建命令生产者Client
public class Client {
public static void main(String[] args) {
// 创建小爱同学
AIInvoker xiaoAIInvoker = new XiaoAIInvoker();
// 创建关灯指令 并指定谁来完成
Command closeBulbCommand = new CloseBulbCommand(new BedRoomBulbRecevier());
xiaoAIInvoker.action(closeBulbCommand);
}
}
测试结果:
到这里,一个简单的小爱同学控制开关关闭的模型就完成了。
二、设计思路
1. 类图设计
参与角色:
- 命令发送方(Client): 首先我们肯定是需要一个命令的产生者,在这个业务场景里,我对小爱同学发送一个关灯指令,那么命令的产生者就是我,而在正常的产品模型中,这个命令的产生者往往是客户端。
- 命令执行者(Invoker): 负责接受业务端发送的所有命令,并且分析命令,将命令委托给对应的业务模块进行处理。
- 命令(command):命令就很好理解了,简单的来说就是我们下达的指令。
- 命令接受者(Recevier):负责执行client下达的指令,负责具体业务逻辑的实现。
2. 撤销操作
有些时候我们在发出一个指令后又后悔了,这个时候我们就需要对应的为invoker提供一个撤销操作的命令。具体的实现方式有两种:
- 通过备忘录模式还原最后状态(这个会在备忘录模式里提及)
- 增加一个反向操作的接口
增加反向操作的接口理解起来其实很简单,比如你提供一个开灯的执行命令就可以再撤销接口里对应的增加一个关灯的,简而言之就是可以通过撤销接口将数据状态恢复到执行命令之前。
3. 命令模式的特点
优点:
- 类间解耦
- 拓展性高
- 可以配合责任链模式实现命令族解析任务,配合模板方法模式减少子类膨胀问题。
缺点:
- 子类膨胀问题
4. 命令模式的使用场景
只要是你认为是命令的地方,都可以采用命令模式。
三、结语
今天的代理模式讲解就全部结束了,设计模式的相关代码已经在gitee上收录,有需求的小伙伴可以直接拿走:
有疑问的小伙伴欢迎评论区留言或者私信博主,博主会在第一时间为你解答。
码字不易,感到有收获的小伙伴记得要关注博主一键三连,不要当白嫖怪哦~
博主在这里祝大家可以在新的一年升职加薪,走上人生巅峰!