微信关注公众号 JavaStorm 获取最新内容。


装饰器模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活;它允许向一个现有的对象添加新的功能,同时又不改变其结构。==装饰器模式属于结构型模式==。

UML 类图



* Component:接口,定义一个抽象接口装饰对象与真实对象具有相同的接口,以便装饰器动态的添加职责。
* ConcreteComponent: 接口的具体对象。
* Decorator:装饰类,继承了 Component , 从外类来拓展 Component 的功能 并且持有一个 Component
的引用,通过构造器实例化,从而实现对真实对象的职责装饰增强。
* ConcreteDecorator:具体装饰类,用于给实际对象添加职责。
使用场景

现在有一个场景:煎饼果子,科技园上班族早上去买煎饼果子(Pancake),有的人要加鸡蛋 (Egg)、有的人加火腿 (Ham)、有的人加生菜
(Lettuce)。有的土豪煎饼果子来一套全都要。现在我们来定义煎饼烹饪实现。(ps:留一个功能读者自己实现:不同的套餐价格是不一样的,如何计算出不同煎饼果子的价格?有兴趣的读者可以留言或者微信公众号后台留言)。

代码实现

代码可以左右滑动

* 先定义煎饼接口也就是我们的被装饰类,以及烹饪的方法 。 package com.zero.headfirst.decorator; public
interface Pancake { /** * 烹饪方法 */ void cook(); }
* 定义一个乞丐版煎饼,被装饰对象。 package com.zero.headfirst.decorator; /** *
被装饰对象:定义最基本的乞丐版煎饼,啥都没加 */ public class BeggarPancake implements Pancake {
@Override public void cook() { System.out.println("乞丐版基本煎饼"); } }
* 定义抽象装饰类 煎饼果子装饰器 PancakeDecorator:抽象装饰器角色,实现煎饼接口(被装饰器接口),持有被装饰器的引用
(pancake)将烹饪行为转发具体的装饰器。 package com.zero.headfirst.decorator; /** *
抽象装饰器角色,实现煎饼接口(被装饰器接口),持有被装饰器的引用将烹饪行为转发具体的装饰器。 */ public abstract class
PancakeDecorator implements Pancake { private Pancake pancake; public
PancakeDecorator(Pancake pancake) { this.pancake = pancake; } @Override public
void cook() { if (pancake != null) { pancake.cook(); } } }
*
各种具体装饰类对乞丐版煎饼进行不等级别的土豪加工。首先继承 抽象出来的 PancakeDecorator ,重写 cook 方法,实现加工。

EggDecorator 鸡蛋装饰器:继承 PancakeDecorator,重写 cook 方法。动态添加鸡蛋,然后调用pancake 的cook。
package com.zero.headfirst.decorator; /** *
鸡蛋装饰器:覆盖cook方法,加入自身的实现,并且调用父类的cook方法,也就是构造函数中 * EggDecorator(Pancake
pancake),这里传入的pancake的cook操作 */ public class EggDecorator extends
PancakeDecorator { public EggDecorator(Pancake pancake) { super(pancake); }
@Override public void cook() { System.out.println("加一个鸡蛋;"); super.cook(); } }
火腿装饰器: HamDecorator
package com.zero.headfirst.decorator; /** * 火腿装饰器 */ public class HamDecorator
extends PancakeDecorator { public HamDecorator(Pancake pancake) {
super(pancake); } @Override public void cook() { System.out.println("加一个火腿;");
super.cook(); } }
生菜装饰器
package com.zero.headfirst.decorator; /** * 生菜装饰器 */ public class
LettuceDecorator extends PancakeDecorator { public LettuceDecorator(Pancake
pancake) { super(pancake); } @Override public void cook() {
System.out.println("加生菜;"); super.cook(); } }
* 定义一个煎饼果子摊位。 package com.zero.headfirst.decorator; /** * 煎饼果子店 */ public
class PancakeShop { public static void main(String[] args) {
System.out.println("========土豪来了,全都加上。======"); BeggarPancake beggarPancake =
new BeggarPancake(); EggDecorator eggDecorator = new
EggDecorator(beggarPancake); HamDecorator hamAndEggDecorator = new
HamDecorator(eggDecorator); LettuceDecorator lettuceAndHamAndEggDecorator = new
LettuceDecorator(hamAndEggDecorator); lettuceAndHamAndEggDecorator.cook();
System.out.println("========苦逼码农来了,只要鸡蛋补补脑。====="); BeggarPancake
beggarPancake1 = new BeggarPancake(); EggDecorator eggDecorator1 = new
EggDecorator(beggarPancake1); eggDecorator1.cook(); } }
* 运行结果 ========土豪来了,全都加上。====== 加生菜; 加一个火腿; 加一个鸡蛋; 乞丐版基本煎饼
========苦逼码农来了,只要鸡蛋补补脑。===== 加一个鸡蛋; 乞丐版基本煎饼
总结

真实世界的装饰: Java I/O。
注意事项与要点

* 抽象装饰器与具体被装饰对象实现同一个接口。
* 抽象装饰器持有被装饰器接口对象,以便请求传递。
* 具体装饰器需要重写抽象装饰器的方法并引用super进行条用,转发请求。
适用场景

*
拓展一个类的功能。

*
动态的添加与撤销职责。

### 优点

* 装饰类与被装饰类只关心自己的核心逻辑,实现了解耦。
* 方便动态拓展,开闭原则。且比继承灵活。
缺点

* 如果功能拓展太多,将产生大量的类。
* 多层装饰会变得复杂。
以上代码可参考我的 GitHub :
https://github.com/UniqueDong/zero-design-stu。headfirst包下。欢迎关注公众号: JavaStorm
获取最新文章,也可在后台留言提出意见。收藏与关注是最大的鼓励。


友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信