装饰者模式
# 装饰者模式
# 模式简介
装饰者模式(Decorator Pattern)是一种结构型设计模式,允许在不修改原有对象的情况下,动态地为对象添加额外职责。
其核心思想是通过组合而非继承来扩展功能,符合开闭原则(对扩展开放,对修改关闭)。
适用场景:
- 需要动态添加或移除功能
- 避免类爆炸(继承层级过多)
# 核心角色与代码结构
# 1. Component(抽象组件)
- 定义
被装饰对象
和装饰器
的公共接口。
/**
* 饮品抽象基类
* 装饰者模式的基础类定义,提供了基本的属性和方法(如des、price、cost()等)
*
* @author chenmeng
*/
@Data
public abstract class AbstractDrink {
// 描述
public String des;
// 单价
private float price = 0.0f;
// 计算费用的抽象方法
// 子类来实现
public abstract float cost();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 2. ConcreteComponent(具体组件)
- 实现基础功能的实体类。(被装饰对象)
/**
* 美式咖啡(咖啡种类,具体饮品) -- 被装饰对象
*
* @author chenmeng
*/
public class LongBlack extends BaseCoffee {
public LongBlack() {
setDes(" longBlack ");
setPrice(5.0f);
}
}
/**
* 无因咖啡(具体饮品) -- 被装饰对象
*
* @author chenmeng
*/
public class DeCaf extends BaseCoffee {
public DeCaf() {
setDes(" 无因咖啡 ");
setPrice(1.0f);
}
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 3. Decorator(装饰抽象类)
- 维护对
被装饰对象
的引用,并提供与 Component 相同的接口。
/**
* 装饰器基类,用于动态地为Drink对象添加功能
*
* @author chenmeng
*/
public class BaseDecorator extends AbstractDrink {
// Decorator类是装饰者模式中的核心抽象类,它通过组合的方式将装饰功能与被装饰对象解耦,
// 使得可以在不修改原有类的情况下动态地扩展功能。这种设计模式非常适合需要灵活扩展功能的场景。
/**
* 被装饰的对象(即需要增强功能的具体饮品)
*/
private final AbstractDrink obj;
public BaseDecorator(AbstractDrink obj) { // 组合
this.obj = obj;
}
@Override
public float cost() {
// getPrice 自己价格
return super.getPrice() + obj.cost();
}
@Override
public String getDes() {
// 自身描述 + 被装饰对象描述,obj.getDes() 输出被装饰者的信息
return des + "+" + getPrice() + " 和 " + obj.getDes();
}
}
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
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
# 4. ConcreteDecorator(具体装饰器)
- 为 Component 添加具体功能。
/**
* 调料
* 具体的装饰器类,继承自Decorator,并实现特定的功能(如添加牛奶、豆浆或巧克力)。
*
* @author chenmeng
*/
public class Chocolate extends BaseDecorator {
public Chocolate(AbstractDrink obj) {
super(obj);
// 设置装饰描述
setDes("巧克力");
// 设置装饰价格
setPrice(3.0f);
}
}
/**
* 牛奶装饰器类
*
* @author chenmeng
*/
public class Milk extends BaseDecorator {
public Milk(AbstractDrink obj) {
super(obj);
// 设置装饰描述
setDes("牛奶");
// 设置装饰价格
setPrice(2.0f);
}
}
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
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
# 代码实现解析
# 1. 基础类关系
- AbstractDrink:定义饮品的基本属性和方法。
- BaseCoffee:继承自 AbstractDrink,实现基础饮品的
cost()
方法(直接返回自身价格)。 - BaseDecorator:继承自 AbstractDrink,通过组合持有
obj
(被装饰对象),并实现功能叠加。
# 2. 装饰器组合逻辑
以 CoffeeBar.java
为例:
/**
* 装饰者模式的客户端测试
*
* @author chenmeng
*/
public class CoffeeBar {
public static void main(String[] args) {
// 测试案例1:LongBlack + 牛奶 + 巧克力
testLongBlackWithAdditions();
System.out.println("======================================================");
// 测试案例2:无因咖啡 + 牛奶
testDecafWithMilk();
}
// 初始订单(LongBlack),费用 = 5.0
// 初始订单(LongBlack),描述 = LongBlack
// 添加牛奶后,费用 = 7.0
// 添加牛奶后,描述 = 牛奶+2.0 和 LongBlack
// 添加巧克力后,费用 = 10.0
// 添加巧克力后,描述 = 巧克力+3.0 和 牛奶+2.0 和 LongBlack
// 再添加巧克力后,费用 = 13.0
// 再添加巧克力后,描述 = 巧克力+3.0 和 巧克力+3.0 和 牛奶+2.0 和 LongBlack
// ======================================================
// 初始订单(无因咖啡),费用 = 1.0
// 初始订单(无因咖啡),描述 = 无因咖啡
// 添加牛奶后,费用 = 3.0
// 添加牛奶后,描述 = 牛奶+2.0 和 无因咖啡
/**
* 测试基础咖啡添加多种调料
*/
private static void testLongBlackWithAdditions() {
AbstractDrink order = new LongBlack();
printOrderStatus(order, "初始订单(LongBlack)");
// 添加牛奶
order = new Milk(order);
printOrderStatus(order, "添加牛奶后");
// 添加第一份巧克力
order = new Chocolate(order);
printOrderStatus(order, "添加巧克力后");
// 再添加一份巧克力
order = new Chocolate(order);
printOrderStatus(order, "再添加巧克力后");
}
/**
* 测试无因咖啡添加牛奶
*/
private static void testDecafWithMilk() {
AbstractDrink order = new DeCaf();
printOrderStatus(order, "初始订单(无因咖啡)");
// 添加牛奶
order = new Milk(order);
printOrderStatus(order, "添加牛奶后");
}
/**
* 打印当前订单状态
*/
private static void printOrderStatus(AbstractDrink drink, String step) {
System.out.println(step + ",费用 = " + drink.cost());
System.out.println(step + ",描述 = " + drink.getDes());
}
}
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
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
# 3. 关键方法实现
BaseDecorator.cost()
:return super.getPrice() + obj.cost();
1自身价格 + 被装饰对象的总价。
BaseDecorator.getDes()
:return des + "+" + getPrice() + " 和 " + obj.getDes();
1自身描述 + 被装饰对象的描述(递归拼接)。
# 模式优势与适用场景
# 1. 核心优势
- 动态扩展:无需修改原有代码,通过组合灵活添加功能。
- 避免继承层级爆炸:通过装饰器链替代多重继承。
- 解耦功能:装饰器与被装饰对象独立,便于维护。
# 2. 适用场景
- 需要动态增减功能的场景(如饮品调料、UI组件特效)。
- 需要实现与继承类似的扩展,但继承层级过多时。
# 3. 注意事项
- 性能开销:过多装饰器可能导致对象链过长。
- 依赖顺序:装饰器的添加顺序会影响最终结果(如价格和描述的拼接顺序)。
# 总结
通过装饰者模式,我们实现了饮品系统的动态功能扩展:
- 基础饮品(如
LongBlack
)提供核心功能。 - 装饰器(如
Milk
、Chocolate
)按需添加调料。 - 客户端通过
链式调用
组合装饰器,灵活生成最终产品。
此模式在 Java 中广泛应用于 IO 流(如 DataInputStream
装饰 FileInputStream
)、UI 框架等场景,是实现 “灵活扩展” 的利器。
上次更新: 2025/3/17 17:25:48