沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 设计须知

  • UML画图

  • 权限校验

  • 设计模式

    • 设计模式基础入门
    • 设计模式七大原则
    • 单例模式
    • 工厂模式
    • 原型模式
    • 建造者模式
    • 适配器模式
    • 桥接模式
    • 装饰者模式
      • 模式简介
      • 核心角色与代码结构
        • 1. Component(抽象组件)
        • 2. ConcreteComponent(具体组件)
        • 3. Decorator(装饰抽象类)
        • 4. ConcreteDecorator(具体装饰器)
      • 代码实现解析
        • 1. 基础类关系
        • 2. 装饰器组合逻辑
        • 3. 关键方法实现
      • 模式优势与适用场景
        • 1. 核心优势
        • 2. 适用场景
        • 3. 注意事项
      • 总结
    • 外观模式
    • 模板方法模式
    • 常见设计模式总结
    • 设计模式 13 问
  • 系统设计
  • 设计模式
沉梦听雨
2025-03-17
目录

装饰者模式

# 装饰者模式

# 模式简介

装饰者模式(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. 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

# 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

# 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

# 代码实现解析

# 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

# 3. 关键方法实现

  • BaseDecorator.cost():

    return super.getPrice() + obj.cost();  
    
    1

    自身价格 + 被装饰对象的总价。

  • BaseDecorator.getDes():

    return des + "+" + getPrice() + " 和 " + obj.getDes();
    
    1

    自身描述 + 被装饰对象的描述(递归拼接)。

# 模式优势与适用场景

# 1. 核心优势

  • 动态扩展:无需修改原有代码,通过组合灵活添加功能。
  • 避免继承层级爆炸:通过装饰器链替代多重继承。
  • 解耦功能:装饰器与被装饰对象独立,便于维护。

# 2. 适用场景

  • 需要动态增减功能的场景(如饮品调料、UI组件特效)。
  • 需要实现与继承类似的扩展,但继承层级过多时。

# 3. 注意事项

  • 性能开销:过多装饰器可能导致对象链过长。
  • 依赖顺序:装饰器的添加顺序会影响最终结果(如价格和描述的拼接顺序)。

# 总结

通过装饰者模式,我们实现了饮品系统的动态功能扩展:

  1. 基础饮品(如LongBlack)提供核心功能。
  2. 装饰器(如Milk、Chocolate)按需添加调料。
  3. 客户端通过 链式调用 组合装饰器,灵活生成最终产品。

此模式在 Java 中广泛应用于 IO 流(如 DataInputStream 装饰 FileInputStream)、UI 框架等场景,是实现 “灵活扩展” 的利器。

上次更新: 2025/3/17 17:25:48
桥接模式
外观模式

← 桥接模式 外观模式→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式