# 装饰者模式
定义:在不改变原有对象的基础之上,将功能附加到对象上
提供了比继承更有弹性的替代方案(扩展原有对象功能)
类型:结构型
生活中的例子:房子装修,礼品包装盒等
# 适用场景
- 扩展一个类的功能或给一个雷添加附加职责
- 动态的给一个对象添加功能,这些功能可以再动态的撤销
# 优点
继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能
继承是写死的,而装饰可以根据使用者自行组合。
通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
符合开闭原则
# 缺点
- 会出现更多的代码,更多的类,增加程序复杂性
- 动态装饰时,多层装饰时会更复查
# 相关设计模式
- 代理模式:关注于控制对对象的访问
- 适配器模式:适配器和被适配的类具有不同的接口,有部分是可能重合的。
# 代码
场景代入:吃早餐,买煎饼,加烤肠、鸡蛋 价格计算是如何的?
# 不适用模式
/**
* 煎饼
*
* @author : zhuqiang
* @date : 2018/12/24 15:39
*/
public class Battercake {
protected String getDesc() {
return "煎饼";
}
/** 费用 */
protected int getCost() {
return 8;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 加鸡蛋的煎饼
*
* @author : zhuqiang
* @date : 2018/12/24 15:41
*/
public class BattercakeWithEgg extends Battercake {
@Override
protected String getDesc() {
return super.getDesc() + " 加一个鸡蛋";
}
@Override
protected int getCost() {
return super.getCost() + 1;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 加鸡蛋和香肠的煎饼
*
* @author : zhuqiang
* @date : 2018/12/24 15:43
*/
public class BattercakeWithEggSausage extends BattercakeWithEgg {
@Override
protected String getDesc() {
return super.getDesc() + " 加一根香肠";
}
@Override
protected int getCost() {
return super.getCost() + 2;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
测试
@Test
public void fun1() {
Battercake battercake = new Battercake();
System.out.println(battercake.getDesc() + " 花费 " + battercake.getCost());
BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
System.out.println(battercakeWithEgg.getDesc() + " 花费 " + battercakeWithEgg.getCost());
BattercakeWithEggSausage battercakeWithEggSausage = new BattercakeWithEggSausage();
System.out.println(battercakeWithEggSausage.getDesc() + " 花费 " + battercakeWithEggSausage.getCost());
}
=========================
煎饼 花费 8
煎饼 加一个鸡蛋 花费 9
煎饼 加一个鸡蛋 加一根香肠 花费 11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这几个顾客的购买需求都能满足,如果有一个顾客需要加 2 个鸡蛋的呢?这就没有办法了
# 使用模式的代码
/**
* 被装饰者抽象类 - 煎饼
*
* @author : zhuqiang
* @date : 2018/12/24 15:49
*/
public abstract class ABattercake {
protected abstract String getDesc();
/**
* 费用
*/
protected abstract int getCost();
}
/**
* 煎饼
*
* @author : zhuqiang
* @date : 2018/12/24 15:39
*/
public class Battercake extends ABattercake {
@Override
protected String getDesc() {
return "煎饼";
}
@Override
protected int getCost() {
return 8;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 装饰者抽象类
*
* @author : zhuqiang
* @date : 2018/12/24 15:51
*/
public class ABattercakeDecorator extends ABattercake {
protected ABattercake battercake;
// 通过构造传入一个抽象煎饼,这样 装饰者和被装饰者就建立起了联系
public ABattercakeDecorator(ABattercake battercake) {
this.battercake = battercake;
}
@Override
protected String getDesc() {
return this.battercake.getDesc();
}
@Override
protected int getCost() {
return this.battercake.getCost();
}
}
/**
* 加鸡蛋的装饰器
*
* @author : zhuqiang
* @date : 2018/12/24 15:56
*/
public class EggDecorator extends ABattercakeDecorator {
public EggDecorator(ABattercake battercake) {
super(battercake);
}
@Override
protected String getDesc() {
return super.getDesc() + " 加一个鸡蛋";
}
@Override
protected int getCost() {
return super.getCost() + 1;
}
}
/**
* 加香肠的装饰器
*
* @author : zhuqiang
* @date : 2018/12/24 15:57
*/
public class SausageDecorator extends ABattercakeDecorator {
public SausageDecorator(ABattercake battercake) {
super(battercake);
}
@Override
protected String getDesc() {
return super.getDesc() + " 加一根香肠";
}
@Override
protected int getCost() {
return super.getCost() + 2;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
测试
@Test
public void fun2() {
ABattercake battercake;
battercake = new Battercake(); // 一个标准煎饼
battercake = new EggDecorator(battercake); // 加一个鸡蛋的
battercake = new EggDecorator(battercake); // 再加一个鸡蛋的
battercake = new SausageDecorator(battercake); // 在加一根香肠的
System.out.println(battercake.getDesc() + " 花费 " + battercake.getCost());
}
=====================
煎饼 加一个鸡蛋 加一个鸡蛋 加一根香肠 花费 12
2
3
4
5
6
7
8
9
10
11
12
13
可以看出来这个结构,装饰器也是被装饰者类型,但是它是持有被装饰者, 这样就可以无限装饰。
对于这里的抽象装饰类来说,没有抽象相关的成员也能完成功能,那么这里的抽象装饰类存在的意义不太大。
一般在有额外的功能的时候需要具体的装饰者实现的时候意义才大,这个就要取决于使用场景和需求了,比如,在制作烤肠煎饼的时候,需要额外的动作功能等。
# 源码解析
spring-session mybatis jdk servlet
java.io.BufferedReader
// 继承 Reader
public class BufferedReader extends Reader {
// 持有 Reader
private Reader in;
// 通过构造传入
public BufferedReader(Reader in, int sz) {
super(in);
2
3
4
5
6
7
8
9
org.springframework.cache.transaction.TransactionAwareCacheDecorator
//实现 Cache ,并持有(组合) Cache
public class TransactionAwareCacheDecorator implements Cache {
private final Cache targetCache;
public TransactionAwareCacheDecorator(Cache targetCache) {
Assert.notNull(targetCache, "Target Cache must not be null");
this.targetCache = targetCache;
}
2
3
4
5
6
7
8
javax.servlet.ServletRequestWrapper
// 基本上都是如此,实现/继承被装饰者,并持有它
public class ServletRequestWrapper implements ServletRequest {
private ServletRequest request;
public ServletRequestWrapper(ServletRequest request) {
if (request == null) {
throw new IllegalArgumentException("Request cannot be null");
}
this.request = request;
}
2
3
4
5
6
7
8
9
10
org.springframework.session.web.http.SessionRepositoryFilter.SessionRepositoryRequestWrapper
也是,看下面的类图
适配器模式和装饰者模式有时候也统称包装模式
org.apache.ibatis.cache.decorators 该包下面的都是装饰器,对缓存接口 org.apache.ibatis.cache.Cache 的装饰;
比如:org.apache.ibatis.cache.decorators.FifoCache 先进先出
public class FifoCache implements Cache {
// 被装饰者,也是委派对象
private final Cache delegate;
private Deque<Object> keyList;
private int size;
public FifoCache(Cache delegate) {
this.delegate = delegate;
this.keyList = new LinkedList<Object>();
this.size = 1024;
}
2
3
4
5
6
7
8
9
10
11