Luckylau's Blog

设计模式之装饰器模式

​ 装饰器模式(Decorator Pattern)以客户端透明的方式扩展对象的功能。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装,是继承关系的一个替代方案。说到装饰者模式,估计大家都不陌生,Java I/O的设计就是采用了装饰者模式。想必初学Java I/O的时候大家都经历过一段“懵逼”期,各种InputStreamOutputStream层层嵌套,感觉就像洋葱,如果给装饰者一个形象化的吉祥物,想必非洋葱莫属。

装饰模式主要包含四个角色:

抽象构件(Component):可以是一个接口或者抽象类,充当被装饰类的原始对象,规定了被装饰类的行为。
具体构件(ConcreteComponent): 实现/继承 Component的一个具体对象,即被装饰对象。通过装饰角色为其添加一些职责。
抽象装饰器(Decorator): 实现/继承 Component。通用的 ConcreteComponent的装饰列,其内部必然有一个属性指向 Component,主要是可以通过其子类扩展具体组件的功能。
具体装饰器(ConcreteDecorator): Decorator的具体实现类,并给具体构件对象添加附加的责任,一般为其特有的功能。

抽象构件:

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
/**
* @className: Drink
* @description:
* @author: charon
* @create: 2022-03-19 22:48
*/
public abstract class Drink {
/**
* 描述
*/
public String desc;
/**
* 价格
*/
private float price = 0.0f;
/**
* Gets the value of desc
*
* @return the value of desc
*/
public String getDesc() {
return desc;
}
/**
* Sets the desc
*
* @param desc desc
*/
public void setDesc(String desc) {
this.desc = desc;
}
/**
* Gets the value of price
*
* @return the value of price
*/
public float getPrice() {
return price;
}
/**
* Sets the price
*
* @param price price
*/
public void setPrice(float price) {
this.price = price;
}
/**
* 计算费用的方法,交给子类实现
* @return
*/
public abstract float cost();
}

具体构件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Coffee extends Drink{
@Override
public float cost() {
return super.getPrice();
}
}
public class LongBlack extends Coffee{
public LongBlack() {
setDesc("美式咖啡");
setPrice(5.0f);
}
}
public class Decaf extends Coffee{
public Decaf() {
setDesc("无因咖啡");
setPrice(1.0f);
}
}

抽象装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Decorator extends Drink{
/**
* 使用聚合的方式
*/
private Drink drink;
public Decorator(Drink drink) {
this.drink = drink;
}
@Override
public float cost() {
return super.getPrice() + drink.cost();
}
@Override
public String getDesc() {
return super.getDesc() + "&&" + drink.getDesc();
}
}

具体装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Milk extends Decorator {
public Milk(Drink drink) {
super(drink);
setDesc("牛奶");
setPrice(2.0f);
}
}
public class Soy extends Decorator {
public Soy(Drink drink) {
super(drink);
setDesc("豆浆");
setPrice(1.5f);
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Client {
public static void main(String[] args) {
// 点一份美式咖啡
Drink longBlack = new LongBlack();
System.out.println(longBlack.getDesc() + " 费用: " + longBlack.cost());
// 添加一点牛奶
longBlack = new Milk(longBlack);
System.out.println(" 添加了: " + longBlack.getDesc() + " 费用: " + longBlack.cost());
// 再添加一点豆浆
longBlack = new Soy(longBlack);
System.out.println(" 添加了: " + longBlack.getDesc() + " 费用: " + longBlack.cost());
}
}
Luckylau wechat
如果对您有价值,看官可以打赏的!