当应用开发中,咱们要为一个对象在原有功能上进行扩展加强时,每每采用继承的方式,而继承过多时就会使得功能类更加复杂,不利于维护,而设计模式中装饰者模式能够帮助咱们更好对应这种场景,装饰者模式能够作到让对象可以动态地进行功能扩展,而不影响其余对象. 那究竟它是如何实现的呢,又如何实际应用呢,就让咱们一块儿来学习下这个模式吧。html
装饰者模式属于结构型设计模式,首先咱们先了解下装饰者模式的定义。java
In object-oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.设计模式
简而言之, 装饰者模式就是动态地为一个对象扩展额外的功能,不管是动态仍是静态,都不影响相同类的其余对象的行为, 这样使得对象在运行时更加灵活。api
装饰者实现的方式一般为组合或者继承,可让客户端根据需求进行对应的装饰,来达到功能增长的目标。为了简化理解,装饰者模式中装饰一词其实就是给原来的对象添加额外功能。oracle
接下来咱们看下装饰者模式的层次结构和主要角色.ide
Component
抽象组件,最原始,核心的对象,一般为接口或者抽象类.ConcreteComponent
具体组件,对 Component
的实现,也是须要装饰的对象.Decorator
装饰者, 一般为抽象组件的抽象实现, 它的属性必定有私有变量指向 Component
.ConcreteDecorator
具体装饰对象,是 Decorator
的具体实现, 用于将原始,核心的方法装饰加强的类.从图中看到,接口 Component
会有对应的实现类 ConcerateComponent
,要对具体实现类进行功能加强,就须要对应的具体装饰者 ConcreteDecorator
,它经过内部引用 Component
类型的 ConcerateComponent
对象 ,在接口方法的默认实现上,容许添加额外的逻辑和功能代码。微服务
如今咱们用喝咖啡的例子来实现下装饰者模式,假设咱们要买一杯咖啡,须要加糖,加奶,而什么都不加的咖啡与加奶,加糖的价格都不同,咱们就要计算调制一杯加糖加奶的咖啡须要花费多少钱。oop
这里咖啡就是咱们的具体组件 ConcerateComponent
, 奶和糖就是具体装饰对象 ConcreteDecorator
。 为了简单,咱们先建立一个Component
接口类 Drink
, 定义两个方法用来得到价格和描述:post
接着,建立一个 ConcreteComponent
类 Coffee
实现 Drink
接口.学习
如今就须要一个抽象类 DrinkDecorator
,用于扩展实现功能加强.
而后就是实现具体装饰对象 Milk
和 Sugar
.
最后客户端实现制做咖啡的动做:
下图为示例的类图:
能够从上面例子看出,经过添加不一样的材料,价格不一样,而且描述信息也不同,而且添加顺序能够动态改变,甚至不添加,让对象变得十分灵活, 这就是装饰者模式的精髓所在。
装饰者模式一样大量应用在 JDK 源码中,咱们常常能够看到:
FilterInputStream
的一系列实现类,好比 BufferedInputStream
,LineNumberInputStream
,DataInpuStream
。装饰者模式可让程序中对象在运行时中进行功能的加强和移除,而且采用更灵活的组合方式来进行扩展。
优势:
ConcreteComponent
) 相互独立,互不耦合,易于扩展。缺点:
装饰层次过多时会让被装饰的对象更复杂,不容易理解,好比使用 Java I/O 的 DataInputStream
对象读取数据为 Java 基本类型值时会这样使用:
DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
复制代码
程序中如有太多的装饰类,理解和使用上略有难度。
掌握装饰者模式的精髓在于经过一层层的包装,让原来对象的功能更增强大,且包装过程是动态的,灵活能够移除的,到最后仍是会调用到原对象最原始的功能。