基本介绍:
装饰者模式:动态的将新功能附加到对象上,在对象功能扩展方面,它比继承更具有弹性,装饰者模式也体现了开闭原则(ocp),装饰者模式也可以理解为包装模式。
例如: 我们要寄一个手机,发快递我们的操作应该如下
- 类图表示
(1)Component
定义一个抽象类,用于接收动态添加的需求。
(2)ConcreteComponent
ConcreteComponent是我们要动态加上新行为的对象。
(3)Decorator
每一个装饰者都持有一个构件(Component)对象的实例,
也就是说,装饰者有一个实例变量以保存某个Component的引用,
(4)ConcreteDecorator
真正的装饰者,负责给对象添加新的方法和行为。
第一个例子:
被装饰者抽象类:Beverage
被装饰者:Espresso,HouseBlend
装饰者抽象类:CondimentDecorator
装饰者:Mocha
- 具体实现代码
1
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104/**
* 被装饰者的抽象类:饮料
*/
public abstract class Beverage {
String description = "Unknown Beverage";
//成本
public abstract double cost();
//得到描述信息
public String getDescription(){
return description;
}
}
/**
* 被装饰者:浓咖啡
*/
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 2;
}
}
/**
* 被装饰者:混合咖啡
*/
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend";
}
public double cost() {
return 1;
}
}
/**
* 装饰者的抽象类:调料
*/
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
public double cost() {
return 0;
}
}
/**
* 装饰者:摩卡
*/
public class Mocha extends CondimentDecorator {
//聚合被装饰者,可以传入实现Beverage接口的所有对象
Beverage beverage;
//构造器,初始化beverage
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription()+",Mocha";
}
public double cost() {
//调用被装饰者的成本,加上装饰者的成本
return 3 + beverage.cost();
}
}
/**
* 测试
*/
public class CoffeeTest {
public static void main(String[] args) {
Beverage beverage = new Espresso();
//一杯浓咖啡为2元
System.out.println(beverage.getDescription()+","+beverage.cost());
Beverage beverage1 = new HouseBlend();
//一杯混合咖啡(1)加摩卡(3)为4元
// 在单个混合咖啡中包装了摩卡
beverage1 = new Mocha(beverage1);
System.out.println(beverage1.getDescription()+","+beverage1.cost());
//一杯混合咖啡(1)加摩卡(3)加摩卡(3)为7元
//可以在包装好的基础上再次进行包装
beverage1 = new Mocha(beverage1);
System.out.println(beverage1.getDescription()+","+beverage1.cost());
}
} - 运行结果
我们发现,写的包装起作用了,可以实现包装功用了!
- 类图形式
第二个例子:
- 结构图
- 代码实现
1
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148/**
* 被装饰者抽象类
*/
public abstract class Drink {
public String des;//描述
private float price = 0.0f;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
//计算费用的抽象 方法
public abstract float cost();
}
/**
* 缓冲层
*/
public class Coffee extends Drink {
public float cost() {
return super.getPrice();
}
}
/**
* 被装饰者:意大利咖啡
*/
public class Espresso extends Coffee {
public Espresso(){
setDes("意大利咖啡");
setPrice(6.0f);
}
}
/**
* 装饰者抽象类:
*/
public class Decorator extends Drink {
private Drink obj;
public Decorator(Drink obj) {//组合
this.obj = obj;
}
public float cost() {
//getPrice自己的价格
return super.getPrice() + obj.cost();
}
public String getDes(){
//obj.getDes()被装饰者的信息
return super.des+" "+super.getPrice()+"&&"+obj.getDes();
}
}
/**
* 被装饰者:LongBlack
*/
public class LongBlack extends Coffee {
public LongBlack() {
setDes("LongBlack");
setPrice(5.0f);
}
}
/**
* 被装饰者:ShortBlack
*/
public class ShortBlack extends Coffee {
public ShortBlack() {
setDes("ShortBlack");
setPrice(4.0f);
}
}
/**
* 装饰者:
*/
public class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
setDes("牛奶");
setPrice(2.0f);
}
}
/**
* 装饰者:
*/
public class Soy extends Decorator {
public Soy(Drink obj) {
super(obj);
setDes("豆浆");
setPrice(1.5f);
}
}
/**
* 装饰者:
*/
public class Chocolate extends Decorator {
public Chocolate(Drink obj) {
super(obj);
setDes("巧克力");
setPrice(3.0f);
}
}
public class CoffBar {
public static void main(String[] args) {
//1.点一份LongBlank
Drink order = new LongBlack();
System.out.println("费用1="+order.cost());
System.out.println("描述="+order.getDes());
//2.加一份牛奶
order = new Milk(order);
System.out.println("加入一份牛奶后的费用1="+order.cost());
System.out.println("描述="+order.getDes());
//3.加入一份巧克力
order = new Chocolate(order);
System.out.println("加入一份牛奶,一份巧克力后的费用1="+order.cost());
System.out.println("描述="+order.getDes());
}
} - 运行结果
- 类图形式
java I/O
- 从JDK源码中我们可以发现
1
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//装饰者抽象类类继承了被装饰者:InputStream
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
//聚合了抽象组件componment
protected volatile InputStream in;
/**
* Creates a <code>FilterInputStream</code>
* by assigning the argument <code>in</code>
* to the field <code>this.in</code> so as
* to remember it for later use.
*
* @param in the underlying input stream, or <code>null</code> if
* this instance is to be created without an underlying stream.
*/
//利用构造方法初始化InputStream
protected FilterInputStream(InputStream in) {
this.in = in;
}
----------------------------------------------------------------------------------------
//被装饰者继承抽象类InputStream
public
class FileInputStream extends InputStream
{
.......
}
----------------------------------------------------------------------------------------
//实际的装饰者继承装饰者抽象类
public
class DataInputStream extends FilterInputStream implements DataInput {
...
}小结:
1.装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
2.装饰者类反映 出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)。
3.装饰者可以在被装饰者的行为前面/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
4.你可以用无数个装饰者包装一个组件。
5.装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。