掌握设计模式之装饰者模式

![](http://ww4.sinaimg.cn/large/006tNc79ly1g4ztauvhzej30p00dw45p.jpg)

## 前言

当应用开发中,我们要为一个对象在原有功能上进行扩展增强时,往往采用继承的方式,而继承过多时就会使得功能类更加复杂,不利于维护,而设计模式中装饰者模式可以帮助我们更好对应这种场景,装饰者模式可以做到让对象能够动态地进行功能扩展,而不影响其他对象. 那究竟它是如何实现的呢,又如何实际应用呢,就让我们一起来学习下这个模式吧。

## 模式定义

装饰者模式属于结构型设计模式,首先我们先了解下装饰者模式的定义。

> 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.

简而言之, 装饰者模式就是动态地为一个对象扩展额外的功能,无论是动态还是静态,都不影响相同类的其他对象的行为, 这样使得对象在运行时更加灵活。

装饰者实现的方式通常为组合或者继承,可以让客户端根据需求进行对应的装饰,来达到功能增加的目标。为了简化理解,装饰者模式中装饰一词其实就是给原来的对象添加额外功能。

## 模式结构

接下来我们看下装饰者模式的层次结构和主要角色.

![image-20181105081809413](https://ws4.sinaimg.cn/large/006tNbRwly1fwwvgxjzzbj30fs0aht9o.jpg)

* `Component` 抽象组件,最原始,核心的对象,通常为接口或者抽象类.
* `ConcreteComponent` 具体组件,对 `Component` 的实现,也是需要装饰的对象.
* `Decorator` 装饰者, 通常为抽象组件的抽象实现, 它的属性一定有私有变量指向 `Component`.
* `ConcreteDecorator` 具体装饰对象,是 `Decorator` 的具体实现, 用于将原始,核心的方法装饰增强的类.

从图中看到,接口 `Component` 会有对应的实现类 `ConcerateComponent`,要对具体实现类进行功能增强,就需要对应的具体装饰者 `ConcreteDecorator` ,它通过内部引用 `Component` 类型的 `ConcerateComponent` 对象 ,在接口方法的默认实现上,允许添加额外的逻辑和功能代码。

## 模式实现

现在我们用喝咖啡的例子来实现下装饰者模式,假设我们要买一杯咖啡,需要加糖,加奶,而什么都不加的咖啡与加奶,加糖的价格都不一样,我们就要计算调制一杯加糖加奶的咖啡需要花费多少钱。

这里咖啡就是我们的具体组件 `ConcerateComponent`, 奶和糖就是具体装饰对象 `ConcreteDecorator`。 为了简单,我们先创建一个`Component`接口类 `Drink`, 定义两个方法用来获得价格和描述:

![](http://ww2.sinaimg.cn/large/006tNc79ly1g4ztsfc1a7j311s082q3f.jpg)

接着,创建一个 `ConcreteComponent` 类 `Coffee` 实现 `Drink` 接口.

![](http://ww2.sinaimg.cn/large/006tNc79ly1g4ztspsoi1j311s0j60ua.jpg)

现在就需要一个抽象类 `DrinkDecorator`,用于扩展实现功能增强.
![](http://ww4.sinaimg.cn/large/006tNc79ly1g4ztt8fkmxj311s0q4ju2.jpg)

然后就是实现具体装饰对象 `Milk` 和 `Sugar`.
![](http://ww3.sinaimg.cn/large/006tNc79ly1g4zttu0hu8j30u012edl6.jpg)

最后客户端实现制作咖啡的动作:
![](http://ww2.sinaimg.cn/large/006tNc79ly1g4ztuahwqej316q0kkq6w.jpg)

下图为示例的类图:

![](http://ww4.sinaimg.cn/large/006tNc79ly1g4zsk8axpmj313e0og40u.jpg)

可以从上面例子看出,通过添加不同的材料,价格不同,并且描述信息也不一样,并且添加顺序可以动态改变,甚至不添加,让对象变得十分灵活, 这就是装饰者模式的精髓所在。

## 模式使用场景

装饰者模式同样大量应用在 JDK 源码中,我们经常可以看到:

- JDK 的 IO 操作类, 比如 [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html) 体系下 `FilterInputStream` 的一系列实现类,比如 `BufferedInputStream`,`LineNumberInputStream`,`DataInpuStream`。
- [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-)

装饰者模式可以让程序中对象在运行时中进行功能的增强和移除,并且采用更灵活的组合方式来进行扩展。

## 模式的得与失

**优点**:

* 在不影响其他对象的情况下,动态为单个对象新增功能。
* 装饰类与被装饰类 (`ConcreteComponent`) 相互独立,互不耦合,易于扩展。
* 代替继承方式的功能实现,减少继承类的存在。

**缺点**:

* 装饰层次过多时会让被装饰的对象更复杂,不容易理解,比如使用 Java I/O 的 `DataInputStream` 对象读取数据为 Java 基本类型值时会这样使用:

```java
DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
```

* 程序中若有太多的装饰类,理解和使用上略有难度。

## 结语

掌握装饰者模式的精髓在于通过一层层的包装,让原来对象的功能更加强大,且包装过程是动态的,灵活可以移除的,到最后还是会调用到原对象最原始的功能。

## 参考

* https://www.journaldev.com/1540/decorator-design-pattern-in-java-example
* https://java-design-patterns.com/patterns/decorator/
* 《设计模式之禅》:https://book.douban.com/subject/4260618/
* https://javadoop.com/post/design-pattern

## 推荐阅读

- [掌握设计模式之适配器模式](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896284&idx=1&sn=fee2c9033e4321096d6010bee3c24a50&scene=21#wechat_redirect)
- [需要接口管理的你了解一下?](https://mp.weixin.qq.com/s/9zrcG2Bar6VkcS8brRIx2g)

- [Java 之 Lombok 必知必会](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896258&idx=1&sn=2a7ade9ebac83ec39342fdcfafea5a23&scene=21#wechat_redirect)
- [Java 开发看的 Scala 入门](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896264&idx=1&sn=81f55af3a8f188b5f26eca32eb3865b8&scene=21#wechat_redirect)
- [Java 微服务新生代之 Nacos](https://mp.weixin.qq.com/s?__biz=MzI3NzEwMDAwNg==&mid=2647896272&idx=1&sn=616b338b93e58afcf7303a06db307a3b&scene=21#wechat_redirect)

原文地址:https://www.cnblogs.com/one12138/p/11198210.html

时间: 2024-10-22 13:07:08

掌握设计模式之装饰者模式的相关文章

设计模式 2 —— 装饰者模式

设计模式目录: 设计模式 1 ——观察者模式 设计模式 2 —— 装饰者模式

Design Pattern 设计模式 Decorator 装饰者模式

1 设计一个基类 2 继承这个基类,并包含这个基类的一个对象 3 创建继承类的时候,初始化这个基类,因为是基类指针,所以可以是所有基类的衍生类对象,那么就可以叠加任意多个衍生类对象了. 关键是在衍生类中包含一个基类对象,然后有了继承和包含两重关系,可以使得一个类一个类对象叠加,达到装饰目的. 等于是创建了一个对象指针链表,一个一个对象发挥其相应的作用. 下面程序装饰一个桌子,同时包含释放内存的处理. 关键要知道基类的析构函数必须使用虚函数,为什么? 1 如果基类不是析构函数,那么如果衍生类中包含

java设计模式之 装饰器模式

适AT java设计模式之 装饰器模式 装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,动态给一个对象添提供了额外的功能. 我们通过下面的实例来演示装饰器模式的用法.模拟一个人从想吃饭.找饭店.享受美食.结束吃饭的过程 代码展示: 首先创建一个被修饰的接口 Eat package deco

设计模式之装饰者模式(Decorator)

1.定义 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案 2.类图 Component抽象构件:Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象.在装饰者模式中,必然有一个最基本.最核心.最原始的接口或抽象类充当Component抽象构件. ConcreteComponent具体构件:ConcreteComponent是最核心.最原始.最基本的接口或抽象类的实现,你要装饰的就是它. Decorator装饰角色:一般是一

设计模式之装饰者模式(三)

欢迎大家的持续关注.上一次,我们结合第一篇推导出来的类图,到第二篇根据类图进行实际代码的编写,对装饰者模式有了一个整体的概念以及实战.不知道对你帮助如何呢?小编已经有门道了,看完接下来的一部分,你会恍然大悟,原来实际编码中你一直在用装饰者模式. 真实世界的装饰者:Java I/O 看到标题,是不是就很想往下看,到底是I/O中的什么呢,让你早已经拥有了装饰者模式的实践?就如书上给的描述,你第一次(还有第二次和第三次)看到这些API发出"哇"的惊叹时,放心,你不是唯一收到惊吓的人.下面,我

java_设计模式_装饰者模式_Decorator Pattern(2016-07-28)

装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的结构 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同.装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展. 装饰模式的类图如下: 在装饰模式中的角色有: ● 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象. ● 具体构件(ConcreteComponent)角色

设计模式之装饰者模式

设计模式系列都是学习HeadFirst设计模式得出的学习心得,中间的例子也会采用书中的例子.这里有必要解释一下,在下面星巴克咖啡的例子中,有几种基本的咖啡,还有牛奶.豆浆等等可以向咖啡中添加,这里说明防止下面不懂. 今天我们来了解一下装饰者模式. 回想一下java的io包,各种stream排上倒海,初学者根本分不清楚到底怎么用,眼花缭乱.其实,它的实验遵循了装饰者设计模式.顾名思义,装饰者就可以简单的理解成用一个东西来装饰另一个东西.比如,你要做鱼吃,在你做好出国之后需要加入香菜.我们就可以简单

python设计模式之装饰器模式

装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能. import time def log_calls(func): def wrapper(*args,**kwargs): now=time.time() print("Calling{0} with {1} and {2}

【设计模式】装饰者模式-明月装饰了你的窗子

装饰者模式 使用装饰者模式,可以动态的给一个对象添加一些额外的职责.这适用于,我们只希望给某个对象而不是整个类添加一些功能的场景.通过使用含有某个特定功能的类来"包裹"原始的类,提供给原始的类某些它本身不具备的特性.比如,我们有一杯"茉莉茶",现在加上一颗"柠檬",那我们就有了一杯"柠檬茉莉花茶"."柠檬"作为一个装饰者,提供了"茉莉茶"本身没有的清爽口感.当然,这也带来了一定的负担,你