《装饰器模式》|设计模式系列第10篇
系列:结构型模式 · 装饰器模式(Decorator Pattern)
关键词:动态增强、包装、职责叠加、替代继承、装饰器、组件
一、什么是装饰器模式
装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
属于结构型设计模式。
简单理解:
装饰器就是动态包装原有对象,在不修改原类代码、不使用继承的前提下,给对象叠加新能力。可以多层嵌套包装,随时增加或者移除功能。例如:一杯基础咖啡,可以动态加牛奶、加糖、加奶泡,自由组合配料,而不是创建大量子类(咖啡+牛奶、咖啡+糖、咖啡+牛奶+糖)。
核心意图
动态扩展对象功能;将扩展逻辑从主体类分离,支持功能多层叠加。
适用场景
- 需要动态给对象增加/移除功能
- 不想使用继承扩展,避免子类数量爆炸
- 功能可以自由组合叠加
- 主体类本身稳定,功能点零散多变
⚠️ 缺点预警:多层包装后,对象层次变多,调试困难;产生大量小包装类。
二、UML结构图
角色划分:
- Component(抽象组件):定义核心接口,被装饰对象和装饰器都实现该接口
- ConcreteComponent(具体组件):原始对象,基础核心功能
- Decorator(抽象装饰器):继承/实现Component,持有Component引用,包装原始对象
- ConcreteDecorator(具体装饰器):实现装饰器,添加额外职责
三、Java 完整示例
场景:Coffee 咖啡,基础咖啡为主体,Milk、Sugar 作为装饰配料,动态叠加。
全部变量、输出文字使用英文。
1. Component 抽象组件
public interface Coffee {
String getDescription();
double getPrice();
}
2. ConcreteComponent 具体组件
public class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double getPrice() {
return 2.0;
}
}
3. Decorator 抽象装饰器
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
4. ConcreteDecorator 具体装饰器
// Milk Decorator
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Milk";
}
@Override
public double getPrice() {
return coffee.getPrice() + 0.5;
}
}
// Sugar Decorator
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", Sugar";
}
@Override
public double getPrice() {
return coffee.getPrice() + 0.3;
}
}
5. Client 客户端
public class Client {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription() + " | Price: " + coffee.getPrice());
// add milk
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " | Price: " + coffee.getPrice());
// add sugar
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription() + " | Price: " + coffee.getPrice());
}
}
运行输出:
Simple Coffee | Price: 2.0
Simple Coffee, Milk | Price: 2.5
Simple Coffee, Milk, Sugar | Price: 2.8
可以自由多层嵌套,动态增加任意组合的配料,不需要新建大量咖啡子类。
四、装饰器模式 vs 适配器模式
| 模式 | 目标 | 核心 |
|---|---|---|
| Decorator | 增强原有对象能力,接口不变 | 包装对象,叠加新功能 |
| Adapter | 转换对象接口,改变接口 | 包装对象,适配不兼容接口 |
五、优缺点总结
✅ 优点
- 动态扩展对象功能,运行时自由增加、移除职责
- 功能拆分,每个装饰器只负责单一能力,符合单一职责
- 避免继承带来的类爆炸,功能自由组合
- 主体代码无需改动,符合开闭原则
❌ 缺点
- 多层嵌套包装,调试、排查问题比较麻烦
- 会生成很多小装饰类,增加代码阅读成本
- 装饰顺序会影响最终结果,需要留意
六、框架源码应用
- JDK IO 流:InputStream / OutputStream,BufferedInputStream、DataInputStream 就是装饰器
- Spring
TransactionAwareCacheDecorator - Servlet
HttpServletRequestWrapper
七、小结
装饰器核心:包装原始对象,接口保持不变,动态叠加功能,组合替代继承。
判断要点:想给对象动态叠加多个可选能力,优先装饰器;如果目的是转换接口,则用适配器。
0 条笔记