命令模式将"请求"封装成(命令)对象,以便使用不同的请求、队列或者日志来参数化其他对象。
命令模式也支持撤销的操作。
命令模式是一种行为设计模式,它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。
设计原则
#
- 解耦:命令模式使发起者和接收者解耦。发起者不关心具体的接收者,只需要根据已知的命令对象
执行
execute()
方法即可。
UML简图
#
classDiagram
direction LR
class Invoker {
+Command command
+invoke()
}
Invoker *..> Command
class Command {
<< interface >>
+execute()
+undo()
}
ConcreteCommand ..|> Command
class ConcreteCommand {
Receiver receiver
+execute()
+undo()
}
Receiver <--* ConcreteCommand
class Receiver {
+someOperation()
}
要点
#
- 命令模式将发出请求的对象(调用者)和接收请求的对象(接收者)解耦。
- 被解耦的对象之间通过命令对象沟通,命令对象封装了接收者和一个或者一组动作。
- 调用者通过执行命令对象的
execute()
方法发出请求,这会使得接收者的动作被调用。 - 调用者接收命令作为参数。甚至可以在运行时动态地进行。
- 命令支持撤销。
- 宏命令是命令的简单延伸,允许一次调用多个命令。宏命令也支持撤销。
- 命令也可以用来实现日志和事务系统。How to?
示例代码
#
在本次示例中,假如你有一个家庭影院,你想通过一个“开关”来一键开启家庭影院,按下这个开关后,系统会执行打开空调,调暗灯光,打开CD播放影片等等一系列操作,我们使用命令模式来完成对应的操作。
...适配器模式将一个类的接口,转换成客户期望的另一个接口。
适配器模式可以让原本接口不兼容的类可以合作无间。
设计原则
#
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
- 为交互对象之间的松耦合而努力
- 类应该对拓展开放,而对修改关闭 (开放-关闭原则)
- 依赖抽象,而不依赖具体类 (依赖倒置原则)
UML简图
#
classDiagram
direction LR
class Client{
+Adaptor adaptor
+otherOperations()
}
class Target {
<< Interface >>
operationA()
}
Client *--> Adaptor
Adaptor ..|> Target
Adaptor *..> Adaptee
class Adaptor {
+Adaptee adaptee
operationA()
}
class Adaptee {
<< Interface >>
operationB()
}
要点
#
- 适配器模式,通过创建"适配器"进行接口转换,可以让不兼容的接口变得兼容。
- 适配器模式让客户从接口的实现解耦。
- 注意适配器和装饰模式的区别,适配器改变接口以让其对不兼容的对象可用,
装饰模式是通过继承,赋予类新的行为和"职责"。
- 当需要使用一个现有的类而可用的接口并不适配时,考虑使用适配器模式。
对象适配器和类适配器
...
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤
延迟到子类中。模板方法可以使得子类在不改变算法结构的前提
下,重新 定义算法的某些步骤。
...外观模式提供了一个统一的(简单)接口,用来访问子
系统中的一群接口。外观定义了一个高层接口,让系统更
容易使用。
设计原则
#
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
- 为交互对象之间的松耦合而努力
- 类应该对拓展开放,而对修改关闭 (开放-关闭原则)
- 依赖抽象,而不依赖具体类 (依赖倒置原则)
- "最少知识原则"——只和你的朋友交谈,不要让太多的类耦合在一起。
最少知识原则:定义
#
在设计系统中,不管是任何对象,都需要注意它所交互的类有哪些,并注意这些类是怎么交互的。
最少知识原则希望,在设计系统的过程中,不要让太多的类交杂在一起,免得修改系统中的一部分,
需要修改其他的部分。如果许多部分相互耦合,系统将会变得复杂、脆弱且不易于维护。
最少知识原则:如何遵循?
#
设计系统的过程中,就任何对象而言,在对象的方法内,应该只调用属于一下范畴的方法:
- 对象本身的方法
- 被当作方法参数而传递进来的对象的方法
- 方法内创建或实例化的对象的方法
- 对象的任何组件(域、field)的方法
不要调用从上述方法中返回的对象支持的方法。
请看如下例:
1public float getTemp(){
2 Thermometer thermometer = station.getThermometer();
3 return thermometer.getTemperature();
4}
应该优化为:
1public float getTemp(){
2 return station.getTemperature();
3}
而getTemperature
方法由station
域提供。这样做的好处是,我们
不需要认识Thermometer
对象了。让我们始终保持最小的朋友圈!
最少知识原则:缺点
#
是的,任何事情都是两面。最少知识原则使得系统耦合度降低,减轻了维护成本,
但同时禁止调用中间对象的方法,这不得不让我们制造更多的"包装"类来处理和
其他组件之间的沟通,这可能会导致开发难度增加。
让我们接着回到『外观模式』吧。
UML简图
#

要点
#
- 外观模式中的
Facade
就是那个"密友",它封装了其他要用到的方法,满足了最少知识原则。 - 当要简化并统一一堆接口时,可以使用外观模式。
- 外观将客户从一个复杂的系统中解耦。
- 实现外观,需要将子系统组合进外观中,然后将具体的工作委托给子系统执行。
- 一个复杂的子系统,可以有多个外观。
示例代码
#
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口来访问子系统中的一群接口。外观模式定义了一个高层接口,让子系统更容易使用。
...