JavaSE-设计模式/10.设计模式-装饰者模式
七八个星天外,两三点雨山前。
——辛弃疾《西江月》
## 设计模式-装饰者模式1. 案例引出装饰者模式
星巴克咖啡订单项目
- 咖啡种类:Espresso(意大利浓咖啡)、LongBlack(美式咖啡)、Decaf(无因咖啡)
- 调料:Milk、Chocolate。
- 要求在扩展新的咖啡种类时,
具有良好的扩展性、改动方便、维护方便
使用 OO 的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合。
- 传统实现方式如下:
传统实现方式分析:
- Drink 是一个抽象类,表示抽象饮料。
- description 就是对咖啡的描述, 比如咖啡的名字、受欢迎程度等
- cost() 方法就是计算费用,Drink 类中做成一个抽象方法.
- Decaf 就是单品咖啡, 继承 Drink, 并实重写 cost方法。
- Espress && Milk 就是单品咖啡+调料, 这个组合很多
- 问题: 这样设计会有很多类,当我们增加一个单品咖啡 , 或者一个新的调料 , 类的数量就会倍,就会出现
类爆炸
。
改进传统方案:
- 前面分析到传统方案 因为咖啡单品+调料组合会造成类的倍增,因此可以做改进,将调料内置到 Drink 类,这样就不会造成类数量过多。从而提高项目的维护性:
- 说明: milk,chocolate 可以设计为 Boolean,表示是否要添加相应的调料。
改进后解决星巴克咖啡订单问题的方案分析
- 改进后可以控制类的数量,不至于造成很多的类
在增加或者删除调料种类时,代码的维护量很大
- 考虑到用户可以添加多份 调料时,可以将 hasMilk 返回一个对应 int
- 下面我们看一下设计模式中的装饰模式,见识一下它的力量…
2. 装饰者模式
2.1 装饰者模式定义
- 装饰者模式:
动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性
, 装饰者模式也体现了开闭原则(ocp)。 - 这里提到的动态的将新功能附加到对象和 ocp 原则,在后面的应用实例上会以代码的形式体现。
2.2 装饰者模式原理
装饰者模式就像打包一个快递
主体:比如:陶瓷、衣服,是被装饰者 Component
包装:比如:报纸填充、塑料泡沫、纸板、木板,是装饰着Decorator
- Component 主体:比如类似前面的 Drink
- ConcreteComponent 和 Decorator
- ConcreteComponent:具体的主体,比如前面的各个单品咖啡
- Decorator: 装饰者,比如各调料.
- 在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
2.3 装饰者模式解决星巴克咖啡订单问题
2.4 代码实现
结合着上图来看:
抽象类Drink以及其子类
1 | // 抽象类Drink |
装饰者Decorator着及其子类☆
关键体现在Decorator这个类中:
Decorator继承Drink类
Decorator聚合Drink类
Decorator组合Drink类
1 | // 装饰者 |
测试星巴克咖啡下单
装饰者模式下的订单:2份巧克力+ 1份牛奶的LongBlack
1 | public class CoffeeBar { |
3. 装饰者模式在 JDK IO源码分析
Java 的 IO 结构,FilterInputStream 就是一个装饰者,源码如下,通过源码我们发现FilterInputStream与我们之前的Decorator有以下相同特征:
FilterInputStream装饰者继承InputStream
FilterInputStream装饰者聚合InputStream
FilterInputStream装饰者组合InputStream
1 | public class FilterInputStream extends InputStream { |
下面是JDK IO源码InputStram中的源码的UML类图,你只要了解FilterInputStream类与抽象类InputStream之间的关系(继承,组合,聚合),然后就很容易理解了。