模式定义
装饰器模式允许向一个现有对象添加新的功能,同时又不改变其结构。装饰者可以在所委托被装饰者的行为之前或之后加上自己的行为,以达到自己的目的。
应用场景
需要为一个类动态的添加功能而又不想增加类型体系的时候。
模式角色
Component,抽象构件角色,I/O系统里由InputStream和OutputStream这两个抽象类来担任(注意:Component是用来定义真实对象和装饰对象间相同的接口的)。
ConcreteComponent,具体构件角色(真实对象),I/O系统里由FileInputStream、FileOutputStream等担任(它们要么实现了Component,要么继承了Component)。
Decorator,装饰角色,I/O系统里由FilterInputStream和FilterOutputStream担任,它持有一个Component的引用(具体指的是InputStream和OutputStream)。
ConcreteDecorator,具体装饰角色(Decorator直接子类),I/O系统里由BufferedInputStream或BufferedOutputStream等担任)
举个例子
汉堡女王开了一个汉堡店,主要买以下三种汉堡,这三种汉堡如下:
- WhopperBurger,大汉堡,售价1美元
- SubmarineSandwich,潜艇三明治,售价1.1美元
- Sandwich,三明治,售价0.9美元
同时还提供以下调味品:
- Cheese,奶酪,售价0.9美元
- Beef,牛肉,售价1.6美元
- Bacon,熏猪肉,售价1.5美元
- Chicken,鸡肉,售价1.9美元
- Lettuce,生菜,售价0.7美元
这部开始营业了,客人A点了份潜艇三明治,加牛肉;客人B点了份三明治,加奶酪;客人C点了份大汉堡,加鸡肉和生菜;客人D点了份大汉堡,加熏猪肉和奶酪,要记录点的都是什么,以及每个客人该付多少钱。
代码实现
抽象构件角色
该角色要提供以下功能:
- 记录客人点的是什么;
- 计算客人该付多少钱
抽象出一个接口Burger
1 | package com.rainmonth.pattern.structural.decorator; |
具体构件角色
大汉堡
WhopperBurger.java
1 | package com.rainmonth.pattern.structural.decorator; |
潜艇三明治
SubmarineSandwich.java
1 | package com.rainmonth.pattern.structural.decorator; |
三明治
Sandwich.java
1 | package com.rainmonth.pattern.structural.decorator; |
抽象装饰器角色
调味品类(装饰器基类)
CondimentDecorator.java
1 | package com.rainmonth.pattern.structural.decorator; |
具体装饰器角色
培根,Bacon.java
1 | package com.rainmonth.pattern.structural.decorator; |
牛肉,Beef.java
1 | package com.rainmonth.pattern.structural.decorator; |
奶酪,Cheese.java
1 | package com.rainmonth.pattern.structural.decorator; |
鸡肉,Chicken.java
1 | package com.rainmonth.pattern.structural.decorator; |
生菜,Lettuce.java
1 | package com.rainmonth.pattern.structural.decorator; |
模拟客户点餐
1 | package com.rainmonth.pattern.structural.decorator; |
输出如下
1 | submarine sandwich, Beef |
UML图
上面例子的UML图如下:
总结
上面的例子中,Burger是抽象构件,WhopperBurger、SubmarineSandwich、Sandwich是具体构件(可以被装饰角色装饰的),CondimentDecorator是抽象的装饰器,所有具体的装饰器都要继承或实现CondimentDecorator,具体的构建以及抽象的装饰器都要实现Burger接口。这样就可以在不改变代码的情况下用具体的装饰角色任意装饰具体构建。
从上面的例子及UML图,可以看出装饰器模式有如下优缺点:
优点
- 可以很好的扩展功能,具体表现就是可以随意的为一款主食(大汉堡、潜艇三明治、三明治)添加调味品(Bacon、Beef等)
- ConfidentDecorator和具体的Bacon、Beef等没有发生耦合
缺点
- 很明显,我要加多个调味品的话,就要新建多个对象(多个new),在一定程度上增加了对象使用的复杂性
典型应用
- Java IO 中的InputStream和OutputStream