Part 1 精讲设计模式
1.6 装饰者模式
田超凡
2019年10月25日
1 装饰者模式(Decorator)
装饰者模式是指在不改变原有对象的基础上采用按顺序传递继承父类实例的方式动态附加功能,相比生成子类更灵活。
2 装饰者模式特点
优点:
可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个功能按想要的顺序执行,以实现不同效果,代码扩展性强。
缺点:
更多的类,使程序结构复杂,加重程序结构复杂性。
3 装饰者模式架构
场景引入:在网关拦截时,需要按照获取网关基本参数、日志收集、API接口限流三步按顺序操作,并且后面可能会新增更多处理步骤,假设目前已经存在的第一个环节(获取网关基本参数)相关业务逻辑代码已经编写完毕,现在要求在不改变已实现代码的基础上,在执行完第一个环节后,对该环节的功能进行动态扩展和补充加强,并确保新增的处理环节按照一定的顺序自动执行。
注意:1.需要考虑到后面环节会动态调整和新增处理环节的情况。
2.不能改动和影响到已经编写完毕的环节的业务逻辑代码,确保满足开闭原则(对扩展开放,对修改关闭)。
根据这个场景,可以使用装饰者模式来实现,定义四种角色:
抽象被装饰者(Abstract Decorated):定义一个抽象接口,来规范准备附加功能的类(被装饰者)
被装饰者(Decorated):将要被附加功能的类,实现抽象被装饰者接口
抽象装饰者(Abstract Decorator):持有对被装饰者角色的引用并定义与抽象被装饰者角色一致的接口
装饰者(Decorator):实现抽象装饰者角色,负责对具体构件添加额外功能和具体业务逻辑的执行。
装饰者模式架构设计草图如下:
4 装饰者模式应用场景
4.1 Java I/O 中的装饰者模式
以Java IO操作中的字符输入流组织架构举例,在Java IO操作中的字符输入流组织架构设计就是基于装饰者模式实现的,比如在这个字符输入流的组织架构图中,我们可以知道:
Reader 作为抽象被装饰者,第二层(Reader接口的子接口)作为被装饰者,第三层(Reader子接口的实现类)作为抽象装饰者,第四层(Reader子接口实现类的子类)作为装饰者,负责组织运行不同业务逻辑的代码,从而实现对被装饰者既定功能的动态增强,不论需要新增多少装饰者进行功能增强和调整,也永远不会影响到被装饰者,这就是装饰者模式的精华所在,装饰者模式模型在多重继承关系下体现的非常明显。
4.2 Spring Session 中的装饰者模式
4.3 Mybatis 缓存中的装饰者模式
5 装饰者模式代码实现
定义抽象被装饰者
|
public abstract class GatewayComponent {
|
定义被装饰者
|
public class BasicComponentGateway extends GatewayComponent {
|
定义抽象装饰者
|
public abstract class AbstractDecorator extends GatewayComponent {
|
定义装饰者
|
public class LogDecorator extends AbstractDecorator {
|
使用工厂获取装饰类
|
public class FactoryGateway {
另外一种方式(构造注入上级装饰者实例) ComponentGateway componentGateway = new LimitDecorator(new LogDecorator(new BasicComponentGateway()));
|
补充说明:
装饰者模式和责任链模式的区别:
责任链模式是基于链式数据结构实现操作的,每一个处理器都需要定义下一个处理器的引用,责任链动态组装后只需要获取第一个处理器就可以像链条一样后面的处理器都会按照组装的顺序按序执行。
装饰者模式是针对被装饰者而言的,装饰者具有和被装饰者相同的行为,但是装饰者会对被装饰者的功能进行动态增强,但是不论有多少个装饰者,他们的最终目标都是针对被装饰者已经存在的功能进行完善和补充。
所以从本质上而言,责任链模式和装饰者模式虽然都是行为型设计模式,二者都有扩展性强但是结构复杂度高的特点,但是二者的意义和概念截然不同。责任链模式是链式操作的,一环扣一环不能断开,连缀性执行。装饰者模式是针对一个共同目标(被装饰者)进行功能动态增加,不需要改动被装饰者已经存在的既定的功能代码,提高可扩展性。
装饰者模式一般可以结合工厂模式使用,使用工厂模式动态创建不同类型的装饰者实例来最终实现对被装饰者功能的动态增强。
转载请注明原作者