一、装饰器模式定义
装饰器模式(Decorator Pattern)是一种结构型设计模式,允许在不改变对象结构的情况下,通过动态添加附加功能来扩展对象的行为。其核心思想是通过组合替代继承,在运行时为对象“包裹”一层新功能,类似于“套娃”或“包装礼物”的过程。
关键特点:
- 动态扩展:功能在运行时动态添加,无需修改原有类。
- 透明性:装饰后的对象与原始对象具有相同的接口,客户端无需感知差异。
- 遵循开闭原则:对扩展开放,对修改关闭,通过新增装饰器实现功能增强。
- 灵活组合:多个装饰器可叠加使用,形成功能链。
二、核心角色与结构
装饰器模式包含以下四个角色:
- Component(抽象构件)
- 定义被装饰对象的公共接口,所有具体构件和装饰器需实现此接口。
- 示例:
Coffee
接口定义getDescription()
和cost()
方法。
- ConcreteComponent(具体构件)
- 实现抽象构件的基本功能,是被装饰的原始对象。
- 示例:
SimpleCoffee
实现基础咖啡的描述和价格。
- Decorator(抽象装饰器)
- 持有抽象构件的引用,提供与构件相同的接口,并在方法中调用被装饰对象的方法。
- 示例:
CoffeeDecorator
抽象类包含decoratedCoffee
成员变量,并重写接口方法。
- ConcreteDecorator(具体装饰器)
- 在抽象装饰器基础上添加具体功能,通过继承扩展行为。
- 示例:
MilkDecorator
和SugarDecorator
分别添加牛奶和糖的功能。
UML类图:
Component → ConcreteComponent
Component ← Decorator → ConcreteDecorator
三、实现步骤
- 定义接口:声明对象的基本操作。
public interface Coffee { String getDescription(); double cost(); }
- 实现具体构件:提供基础功能。
public class SimpleCoffee implements Coffee { @Override public String getDescription() { return "普通咖啡"; } @Override public double cost() { return 5.0; } }
- 创建抽象装饰器:持有构件引用并转发调用。
public abstract class CoffeeDecorator implements Coffee { protected Coffee decoratedCoffee; public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; } @Override public String getDescription() { return decoratedCoffee.getDescription(); } @Override public double cost() { return decoratedCoffee.cost(); } }
- 实现具体装饰器:添加额外功能。
public class MilkDecorator extends CoffeeDecorator { public MilkDecorator(Coffee coffee) { super(coffee); } @Override public String getDescription() { return super.getDescription() + " + 牛奶"; } @Override public double cost() { return super.cost() + 2.0; } }
- 客户端使用:通过链式调用装饰器动态扩展功能。
Coffee coffee = new SimpleCoffee(); coffee = new MilkDecorator(coffee); coffee = new SugarDecorator(coffee); System.out.println(coffee.getDescription()); // 普通咖啡 + 牛奶 + 糖
四、应用场景
- 动态功能扩展
- 需要根据运行时条件动态添加或撤销功能(如权限控制、日志记录)。
- 替代继承
- 避免因功能组合导致类爆炸(如咖啡店中咖啡与配料的多种组合)。
- 灵活组合功能
- 多个装饰器叠加使用,形成不同功能组合(如Java I/O流中的
BufferedInputStream
和DataInputStream
)。
- 多个装饰器叠加使用,形成不同功能组合(如Java I/O流中的
- 第三方库适配
- 统一调用不同接口的第三方服务(如支付系统中叠加折扣、优惠券等)。
五、优缺点分析
优点:
- 动态扩展:无需修改原有类,灵活添加功能。
- 降低耦合:通过组合替代继承,避免类层次复杂化。
- 复用性高:装饰器可独立开发和复用。
缺点: - 复杂性增加:装饰器链过长可能导致调试困难。
- 性能损耗:每层装饰器增加调用层级,可能影响性能。
六、JDK中的典型应用
- Java I/O流
BufferedInputStream
、DataInputStream
等装饰器类,通过组合实现缓存、编码等功能。
- Spring框架
- AOP代理通过装饰器模式实现事务管理、日志切面等。
- 集合类工具
Collections.checkedList()
通过装饰器对集合进行边界检查。
七、与代理模式的区别
特征 | 装饰器模式 | 代理模式 |
---|---|---|
目的 | 增强对象功能 | 控制对象访问(如权限、日志) |
接口一致性 | 装饰器与被装饰对象接口一致 | 代理与被代理对象接口一致 |
功能叠加 | 支持多层装饰器叠加 | 通常仅单层代理 |
典型应用 | 功能扩展(如咖啡配料) | 远程调用、事务管理 |
八、总结
装饰器模式通过动态组合实现灵活的功能扩展,适用于需要动态增强对象且避免继承复杂性的场景。其核心是透明接口和链式装饰,但需注意装饰器链的合理设计以避免过度复杂。实际开发中,可结合JDK源码(如I/O流)和框架(如Spring AOP)深入理解其应用价值。