装饰者模式,让你的代码像搭积木一样灵活!
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不改变对象结构的情况下,动态地给对象添加新的功能。
·
想象一下,你有一杯最普通的咖啡,但是你想要加牛奶、加糖、加奶泡…每次都要重新煮一壶?装饰者模式就像是给你的代码穿上了"变身衣",让它可以随意组合各种功能,而不用改动原来的代码!
🤔 什么是装饰者模式?
装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你在不改变对象结构的情况下,动态地给对象添加新的功能。
说人话就是:给你的对象穿上不同的"外套",每件外套都有不同的超能力!
想象你是一个超级英雄:
- 基础形态:普通人
- 穿上战衣:获得飞行能力
- 再戴上手套:获得激光攻击
- 再加个头盔:获得透视能力
每次"装饰"都不会改变你的本质,但会让你变得更强大!
🏠 装饰者模式的应用场景
1. Java IO流 - 经典中的经典
// 看这熟悉的代码,是不是觉得很眼熟?
FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
这就是装饰者模式的典型应用!每一层包装都增加了新的功能:
FileInputStream:基础文件读取BufferedInputStream:加上缓冲功能DataInputStream:加上数据类型转换功能
2. Web中间件
在Spring Boot中,各种Filter和Interceptor也是装饰者模式的体现:
// 给HTTP请求"穿上"各种功能的外套
原始请求 -> 认证Filter -> 日志Filter -> 缓存Filter -> 业务逻辑
3. 咖啡店的点餐系统
最经典的例子,我们用它来讲解原理!

⚙️ 装饰者模式的核心原理
类图结构

代码实现:咖啡店订单系统
1. 基础组件接口
// 咖啡基础接口
public interface Coffee {
String getDescription();
double getCost();
}
2. 具体组件(基础咖啡)
// 美式咖啡 - 最基础的实现
public class Americano implements Coffee {
@Override
public String getDescription() {
return "美式咖啡";
}
@Override
public double getCost() {
return 15.0;
}
}
// 拿铁咖啡
public class Latte implements Coffee {
@Override
public String getDescription() {
return "拿铁咖啡";
}
@Override
public double getCost() {
return 25.0;
}
}
3. 装饰者基类
// 装饰者抽象类 - 关键在于它也实现了Coffee接口
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee; // 持有一个Coffee对象的引用
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public String getDescription() {
return coffee.getDescription();
}
@Override
public double getCost() {
return coffee.getCost();
}
}
4. 具体装饰者(各种配料)
// 牛奶装饰者
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 牛奶";
}
@Override
public double getCost() {
return coffee.getCost() + 3.0;
}
}
// 糖装饰者
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 糖";
}
@Override
public double getCost() {
return coffee.getCost() + 2.0;
}
}
// 奶泡装饰者
public class FoamDecorator extends CoffeeDecorator {
public FoamDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + " + 奶泡";
}
@Override
public double getCost() {
return coffee.getCost() + 5.0;
}
}
5. 客户端使用 - 灵活组合的魅力
public class CoffeeShop {
public static void main(String[] args) {
// 点一杯基础美式
Coffee coffee = new Americano();
System.out.println(coffee.getDescription() + " - ¥" + coffee.getCost());
// 输出:美式咖啡 - ¥15.0
// 给美式加牛奶
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " - ¥" + coffee.getCost());
// 输出:美式咖啡 + 牛奶 - ¥18.0
// 再加糖
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription() + " - ¥" + coffee.getCost());
// 输出:美式咖啡 + 牛奶 + 糖 - ¥20.0
// 最后加奶泡(豪华版!)
coffee = new FoamDecorator(coffee);
System.out.println(coffee.getDescription() + " - ¥" + coffee.getCost());
// 输出:美式咖啡 + 牛奶 + 糖 + 奶泡 - ¥25.0
// 一行代码搞定豪华拿铁!
Coffee luxuryLatte = new FoamDecorator(
new SugarDecorator(
new MilkDecorator(
new Latte()
)
)
);
System.out.println("豪华版:" + luxuryLatte.getDescription() + " - ¥" + luxuryLatte.getCost());
// 输出:豪华版:拿铁咖啡 + 牛奶 + 糖 + 奶泡 - ¥35.0
}
}
🚀 装饰者模式的扩展应用
1. 与其他设计模式的结合
装饰者 + 工厂模式
public class CoffeeDecoratorFactory {
public static Coffee createCoffee(String type, List<String> decorators) {
Coffee coffee = CoffeeFactory.createBaseCoffee(type);
for (String decorator : decorators) {
switch (decorator) {
case "milk":
coffee = new MilkDecorator(coffee);
break;
case "sugar":
coffee = new SugarDecorator(coffee);
break;
case "foam":
coffee = new FoamDecorator(coffee);
break;
}
}
return coffee;
}
}
2. Spring AOP中的装饰者思想
@Service
public class UserService {
@Transactional // 事务装饰
@Cacheable // 缓存装饰
@LogExecution // 日志装饰
public User getUserById(Long id) {
return userRepository.findById(id);
}
}
3. 函数式编程中的装饰者
// 使用Function接口实现装饰者
Function<String, String> addMilk = s -> s + " + 牛奶";
Function<String, String> addSugar = s -> s + " + 糖";
Function<String, String> addFoam = s -> s + " + 奶泡";
// 链式调用
String result = addFoam
.compose(addSugar)
.compose(addMilk)
.apply("美式咖啡");
System.out.println(result); // 美式咖啡 + 牛奶 + 糖 + 奶泡
🎯 面试热点问题
Q1: 装饰者模式和继承有什么区别?
面试官最爱问的经典问题!
| 对比维度 | 继承 | 装饰者模式 |
|---|---|---|
| 扩展时机 | 编译时静态扩展 | 运行时动态扩展 |
| 灵活性 | 固化的类层次结构 | 灵活组合,随意搭配 |
| 类的数量 | 每种组合需要一个子类 | 装饰者可任意组合 |
| 复用性 | 较差,功能绑定在特定类中 | 很好,装饰者可复用 |
举个栗子:
如果用继承实现咖啡店,你需要这些类:
AmericanoWithMilkAmericanoWithSugarAmericanoWithMilkAndSugarAmericanoWithMilkAndSugarAndFoamLatteWithMilk- …(类爆炸💥)
用装饰者模式,只需要几个装饰者类就能搞定所有组合!
Q2: 装饰者模式的优缺点?
优点:
- ✅ 动态组合功能,比继承更灵活
- ✅ 遵循开闭原则,对扩展开放,对修改关闭
- ✅ 可以用多个装饰者包装同一个对象
- ✅ 装饰者和被装饰者可以独立变化
缺点:
- ❌ 装饰者层级过多时,调试困难
- ❌ 创建对象的代码可能变得复杂
- ❌ 装饰链的顺序可能影响结果
Q3: 何时使用装饰者模式?
使用场景:
- 需要在不改变对象结构的情况下,动态地给对象添加功能
- 需要对一批对象进行功能扩展,但用继承会导致类爆炸
- 系统需要支持功能的灵活组合和撤销
经典应用:
- Java I/O 流
- Web 中间件/过滤器
- UI 组件的样式装饰
- 缓存、日志、事务等横切关注点
Q4: 装饰者模式在Spring中的应用?
Spring Framework 大量使用了装饰者模式:
- BeanWrapper - 给Bean添加属性访问功能
- 各种BeanPostProcessor - 在Bean创建过程中添加额外处理
- WebMvcConfigurer - 给MVC配置添加自定义功能
- HandlerInterceptor - 给请求处理添加前置/后置处理
// Spring中的装饰者模式示例
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor()) // 日志装饰
.addInterceptor(new AuthInterceptor()) // 认证装饰
.addInterceptor(new CacheInterceptor()); // 缓存装饰
}
}
💡 总结
装饰者模式就像是给你的代码穿上了"乐高积木"的外衣,让功能可以自由组合,随心所欲!
记住这个口诀:
包装不改本质,组合胜过继承
动态添功能,装饰者最行!
实战建议:
- 当你发现继承层次过深时,考虑装饰者模式
- 当需要灵活组合功能时,装饰者模式是首选
- 注意装饰者的顺序,有时候顺序很重要!
- 不要过度设计,简单问题用简单方案
装饰者模式不仅仅是一种设计模式,更是一种编程思想 - 组合优于继承。掌握了它,你的代码将变得更加灵活和优雅!
更多推荐

所有评论(0)