内功心法专题-设计模式-16、命令模式
1. 模式定义
命令模式(Command Pattern):==将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开==。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。❕
在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可。此时可以使用命令模式来进行设计
2. 模式结构
2.1. ⭐️🔴UML 图示
2.2. ⭐️🔴角色分析
- 抽象命令类(Command)角色: 定义命令的接口,声明执行的方法,可以是接口或抽象类。
- 具体命令(Concrete Command)角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
- 实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
- 调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
3. ⭐️🔴实现逻辑
具体命令角色聚合命令接受者:聚合 + 构造导入
调用者 (请求者) 聚合命令接口:聚合 +setter 导入命令并放在集合中 (餐馆堂食) 或者 构造方法中 new 命令放到集合中 (智能生活)
❕
4. 案例分析
4.1. 餐馆堂食⭐️🔴

将上面的案例用代码实现,那我们就需要分析命令模式的角色在该案例中由谁来充当。
服务员: 就是调用者角色,由她来发起命令。
资深大厨: 就是接收者角色,真正命令执行的对象。
订单: 命令中包含订单。
类图如下:
4.1.1. 示例代码
[[Waitor.java]]
4.1.2. 实现逻辑
具体命令角色聚合命令接受者:聚合 + 构造导入
调用者 (请求者) 聚合命令接口:聚合 +setter 导入命令并放在集合中
4.2. 智能家居⭐️🔴
4.2.1. undoCommand
示例代码:[[RemoteController.java]]
4.2.2. 实现逻辑
具体命令角色聚合命令接受者:聚合 + 构造导入
调用者 (请求者) 聚合命令接口:聚合 + 构造方法中 new 命令放到集合中 (智能家居)
5. ⭐️🔴JDK 源码分析
5.1. Runable
Runable 是一个典型命令模式,Runnable 担当抽象命令的角色,Thread 充当的是调用者,持有 Runnable。start 方法就是其执行方法。我们自定义的 TurnOffThread 类属于具体命令角色,持有命令接收者 Reciver。
1 |
|
会调用一个 native 方法 start0 (),调用系统方法,开启一个线程。而接收者是对程序员开放的,可以自己定义接收者。
1 |
|
5.2. JdbcTemplate ✅
以 JdbcTemplate
类中 query()
方法中为例,我们可以发现其中定义了一个内部类 QueryStatementCallback
,而且 QueryStatementCallback
类实现了 StatementCallback
接口的 doInStatement
方法。这就是命令模式在 Spring 框架 JdbcTemplate
源码中的应用,其中,
StatementCallback
充当了Command
命令,其下有多个实现QueryStatementCallback
充当了ConcreteCommand
具体的命令角色Statement
充当了Receiver
接收者角色JdbcTemplate
本身作为调用者
6. 优缺点⭐️🔴
1. 优点:
- 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。“请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用
- 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
- 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
- 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。
2. 缺点:
- 使用命令模式可能会导致某些系统有过多的具体命令类。
- 系统结构更加复杂。
7. 适用场景⭐️🔴
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销 (Undo) 操作和恢复 (Redo) 操作。
8. 实战经验
- 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦
- 命令模式经典的应用场景:界面的一个按钮对应一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发 - 反馈机制