- 装饰器模式详解
- 什么是装饰器模式?
- 核心思想
- 设计原则体现
- 装饰器模式的结构
- 1. Component (抽象构件)
- 2. ConcreteComponent (具体构件)
- 3. Decorator (抽象装饰器)
- 4. ConcreteDecorator (具体装饰器)
- 装饰器模式的应用场景
- 场景一:运行时动态扩展功能
- 场景二:当继承方案不可行或不适用时
- 场景三:需要撤销功能
- 场景四:核心功能与附加功能分离
- 装饰器模式的优缺点
- 优点
- 缺点
装饰器模式详解
什么是装饰器模式?
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变现有对象结构的情况下,动态地给该对象添加额外的职责或行为。这种模式创建了一个装饰器类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
核心思想
装饰器模式的核心思想是"动态添加功能",就像给一个物体"穿衣服":
- 你可以一层一层地套上不同的衣服(装饰器)
- 每一件衣服都增加一种新的特性(功能)
- 物体的本质(核心功能)并没有改变
这个过程的实现方式是通过创建一个包裹原始对象的"装饰器"对象,而不是通过继承。
设计原则体现
装饰器模式是开闭原则(Open-Closed Principle)的典范应用:
- 开闭原则:软件实体应该对扩展开放,对修改关闭
- 装饰器模式让我们在不修改既有代码的情况下,为对象赋予了无限的扩展可能
装饰器模式的结构
装饰器模式通常包含四个核心角色:
1. Component (抽象构件)
- 这是一个接口或抽象类
- 定义了原始对象和装饰器对象所共有的接口
- 确保它们可以被一致地对待
2. ConcreteComponent (具体构件)
- 这是我们的"裸对象",即被装饰的原始对象
- 它实现了Component接口
- 提供了基本的核心功能
3. Decorator (抽象装饰器)
- 它也实现了Component接口
- 内部持有一个Component类型的引用(即它要装饰的对象)
- 它的存在是为了将装饰逻辑与基础组件分离开
4. ConcreteDecorator (具体装饰器)
- 这是实际的"衣服"
- 它继承自Decorator
- 负责向被装饰的对象添加具体的新功能
- 在实现Component接口的方法时,它除了调用原始对象(通过持有的引用)的相应方法外,还会加上自己的"装饰"逻辑
装饰器模式的应用场景
场景一:运行时动态扩展功能
当我们希望在运行时根据不同条件为对象增添不同功能时,装饰器模式是绝佳选择。
经典示例:Java I/O流
FileInputStream是一个具体构件(原始输入流)- 可以用
BufferedInputStream来装饰它,为其增加缓冲功能以提高性能 - 还可以用
DataInputStream来装饰,进一步为其增加读取基本数据类型的能力 - 这些装饰器可以任意组合,非常灵活
// 装饰器组合使用示例InputStreaminput=newDataInputStream(newBufferedInputStream(newFileInputStream("test.txt")));场景二:当继承方案不可行或不适用时
被final修饰的类:如果一个类被final修饰,我们无法通过继承来扩展它。此时,装饰器模式就成了"救星"。
避免类爆炸:如果功能的组合种类非常多,使用继承会产生大量的子类,导致"类爆炸"问题。而装饰器模式则可以用少量的类灵活组合出所有需要的功能。
示例:咖啡订单系统
- 基础咖啡类:Espresso, DarkRoast
- 调料装饰器:Milk, Mocha, Whip
- 通过装饰器组合可以创建各种咖啡,而不需要为每种组合创建子类
// 创建一杯加双份摩卡和奶油的浓缩咖啡Beveragebeverage=newEspresso();beverage=newMocha(beverage);// 第一份摩卡beverage=newMocha(beverage);// 第二份摩卡beverage=newWhip(beverage);// 加奶油场景三:需要撤销功能
由于装饰器是通过组合而非继承实现的,因此可以方便地添加或移除装饰器来改变对象的行为。
场景四:核心功能与附加功能分离
当希望将核心功能与可选功能分离,保持核心类的简洁时,装饰器模式非常有用。
装饰器模式的优缺点
优点
- 比继承更灵活:可以在运行时动态添加或删除功能
- 避免类爆炸:通过组合少量装饰器类可以实现多种功能组合
- 符合开闭原则:无需修改现有代码即可扩展功能
- 职责分离:将核心功能与装饰功能分开
缺点
- 会产生许多小对象:过度使用会导致系统充满大量小对象
- 调试困难:多层装饰使得调试变得复杂
- 设计复杂:需要设计良好的抽象构件和装饰器层次结构