想象一下,你有一杯最普通的咖啡,但是你想要加牛奶、加糖、加奶泡…每次都要重新煮一壶?装饰者模式就像是给你的代码穿上了"变身衣",让它可以随意组合各种功能,而不用改动原来的代码!

🤔 什么是装饰者模式?

装饰者模式(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: 装饰者模式和继承有什么区别?

面试官最爱问的经典问题!

对比维度 继承 装饰者模式
扩展时机 编译时静态扩展 运行时动态扩展
灵活性 固化的类层次结构 灵活组合,随意搭配
类的数量 每种组合需要一个子类 装饰者可任意组合
复用性 较差,功能绑定在特定类中 很好,装饰者可复用

举个栗子:
如果用继承实现咖啡店,你需要这些类:

  • AmericanoWithMilk
  • AmericanoWithSugar
  • AmericanoWithMilkAndSugar
  • AmericanoWithMilkAndSugarAndFoam
  • LatteWithMilk
  • …(类爆炸💥)

用装饰者模式,只需要几个装饰者类就能搞定所有组合!

Q2: 装饰者模式的优缺点?

优点:

  • ✅ 动态组合功能,比继承更灵活
  • ✅ 遵循开闭原则,对扩展开放,对修改关闭
  • ✅ 可以用多个装饰者包装同一个对象
  • ✅ 装饰者和被装饰者可以独立变化

缺点:

  • ❌ 装饰者层级过多时,调试困难
  • ❌ 创建对象的代码可能变得复杂
  • ❌ 装饰链的顺序可能影响结果

Q3: 何时使用装饰者模式?

使用场景:

  1. 需要在不改变对象结构的情况下,动态地给对象添加功能
  2. 需要对一批对象进行功能扩展,但用继承会导致类爆炸
  3. 系统需要支持功能的灵活组合和撤销

经典应用:

  • Java I/O 流
  • Web 中间件/过滤器
  • UI 组件的样式装饰
  • 缓存、日志、事务等横切关注点

Q4: 装饰者模式在Spring中的应用?

Spring Framework 大量使用了装饰者模式:

  1. BeanWrapper - 给Bean添加属性访问功能
  2. 各种BeanPostProcessor - 在Bean创建过程中添加额外处理
  3. WebMvcConfigurer - 给MVC配置添加自定义功能
  4. HandlerInterceptor - 给请求处理添加前置/后置处理
// Spring中的装饰者模式示例
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())     // 日志装饰
                .addInterceptor(new AuthInterceptor())    // 认证装饰
                .addInterceptor(new CacheInterceptor());  // 缓存装饰
    }
}

💡 总结

装饰者模式就像是给你的代码穿上了"乐高积木"的外衣,让功能可以自由组合,随心所欲!

记住这个口诀:

包装不改本质,组合胜过继承

动态添功能,装饰者最行!

实战建议:

  1. 当你发现继承层次过深时,考虑装饰者模式
  2. 当需要灵活组合功能时,装饰者模式是首选
  3. 注意装饰者的顺序,有时候顺序很重要!
  4. 不要过度设计,简单问题用简单方案

装饰者模式不仅仅是一种设计模式,更是一种编程思想 - 组合优于继承。掌握了它,你的代码将变得更加灵活和优雅!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐