JAVA装饰器模式适用场景,优缺点是什么你知道吗这篇文章彻底讲透

JAVA装饰器模式适用场景,优缺点是什么你知道吗这篇文章彻底讲透

编程文章jaq1232025-07-21 14:54:477A+A-

一句话总结:装饰器模式(Decorator Pattern)动态扩展对象功能,不修改原有代码,避免继承爆炸,是开闭原则的经典实践。


一、适用场景(什么时候用?)

  1. 动态扩展功能:运行时添加或撤销功能(如游戏装备系统、IO流嵌套)。
  2. 避免子类爆炸:当继承导致类数量指数级增长时(如不同咖啡 + 不同调料组合)。
  3. 核心功能与扩展功能解耦:核心类保持稳定,扩展功能通过装饰器叠加(如Servlet的HttpServletRequestWrapper)。

二、代码案例:咖啡订单系统

假设咖啡店有基础咖啡(美式、拿铁),可动态添加调料(牛奶、糖、巧克力)。

// 1. 抽象组件:定义核心功能
public abstract class Coffee {
    public abstract String getDescription();
    public abstract double cost();
}

// 2. 具体组件:基础咖啡
public class Americano extends Coffee {
    @Override public String getDescription() { return "美式咖啡"; }
    @Override public double cost() { return 20.0; }
}

public class Latte extends Coffee {
    @Override public String getDescription() { return "拿铁"; }
    @Override public double cost() { return 25.0; }
}

// 3. 抽象装饰器:继承Coffee,持有Coffee引用
public abstract class CoffeeDecorator extends Coffee {
    protected Coffee decoratedCoffee;
    public CoffeeDecorator(Coffee coffee) { this.decoratedCoffee = coffee; }
}

// 4. 具体装饰器:添加调料
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) { super(coffee); }
    @Override public String getDescription() {
        return decoratedCoffee.getDescription() + " + 牛奶";
    }
    @Override public double cost() { return decoratedCoffee.cost() + 5.0; }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) { super(coffee); }
    @Override public String getDescription() {
        return decoratedCoffee.getDescription() + " + 糖";
    }
    @Override public double cost() { return decoratedCoffee.cost() + 2.0; }
}

// 5. 客户端使用:动态组合功能
public class Client {
    public static void main(String[] args) {
        // 点一杯美式 + 双份糖
        Coffee coffee = new Americano();
        coffee = new SugarDecorator(coffee); // 第一次加糖
        coffee = new SugarDecorator(coffee); // 第二次加糖

        System.out.println(coffee.getDescription()); 
        // 输出:美式咖啡 + 糖 + 糖
        System.out.println("总价: " + coffee.cost()); 
        // 输出:总价: 24.0
    }
}

三、装饰器模式优点

  1. 开闭原则:不修改原有类,通过新增装饰器扩展功能。
  2. 动态组合:运行时自由叠加功能(如 new MilkDecorator(new SugarDecorator(new Americano())))。
  3. 避免继承爆炸:N种基础组件 + M种装饰器 → 仅需 N + M 个类(继承需 N * M 个子类)。
  4. 职责清晰:每个装饰器只关注单一扩展功能(如糖、牛奶独立变化)。

四、装饰器模式缺点

  1. 复杂度增加:多层装饰时代码可读性下降(需逐层包装)。
  2. 设计难度:过度使用会导致大量小类,增加系统理解成本。
  3. 初始化繁琐:创建对象时需逐层包装(可用工厂模式优化)。

五、典型应用场景对比

场景

传统继承方案

装饰器方案

Java I/O 流

无法组合多种流

new BufferedInputStream(new FileInputStream())

Web 请求处理

每个过滤器需改核心类

通过 HttpServletRequestWrapper 包装

游戏角色装备系统

装备组合产生海量子类

装备作为装饰器动态附加


六、为什么选装饰器模式?

  • 继承 vs 装饰器
    • 继承是静态扩展(编译时确定),装饰器是动态扩展(运行时组合)。
  • 装饰器 vs 代理
    • 代理控制访问,装饰器增强功能(代理通常只包装一层,装饰器可多层嵌套)。

七、总结

  • 用装饰器当: 需动态扩展功能、避免破坏原有代码、组合数量未知时。
  • 不用当: 功能扩展是静态的(直接继承)、或扩展会导致过度设计时。

记住这句话:装饰器是“即插即用”的功能扩展插件,用好它,代码更灵活、更干净!

点击这里复制本文地址 以上内容由jaq123整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

苍茫编程网 © All Rights Reserved.  蜀ICP备2024111239号-21