JAVA装饰器模式适用场景,优缺点是什么你知道吗这篇文章彻底讲透
一句话总结:装饰器模式(Decorator Pattern)动态扩展对象功能,不修改原有代码,避免继承爆炸,是开闭原则的经典实践。
一、适用场景(什么时候用?)
- 动态扩展功能:运行时添加或撤销功能(如游戏装备系统、IO流嵌套)。
- 避免子类爆炸:当继承导致类数量指数级增长时(如不同咖啡 + 不同调料组合)。
- 核心功能与扩展功能解耦:核心类保持稳定,扩展功能通过装饰器叠加(如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
}
}
三、装饰器模式优点
- 开闭原则:不修改原有类,通过新增装饰器扩展功能。
- 动态组合:运行时自由叠加功能(如 new MilkDecorator(new SugarDecorator(new Americano())))。
- 避免继承爆炸:N种基础组件 + M种装饰器 → 仅需 N + M 个类(继承需 N * M 个子类)。
- 职责清晰:每个装饰器只关注单一扩展功能(如糖、牛奶独立变化)。
四、装饰器模式缺点
- 复杂度增加:多层装饰时代码可读性下降(需逐层包装)。
- 设计难度:过度使用会导致大量小类,增加系统理解成本。
- 初始化繁琐:创建对象时需逐层包装(可用工厂模式优化)。
五、典型应用场景对比
场景 | 传统继承方案 | 装饰器方案 |
Java I/O 流 | 无法组合多种流 | new BufferedInputStream(new FileInputStream()) |
Web 请求处理 | 每个过滤器需改核心类 | 通过 HttpServletRequestWrapper 包装 |
游戏角色装备系统 | 装备组合产生海量子类 | 装备作为装饰器动态附加 |
六、为什么选装饰器模式?
- 继承 vs 装饰器:
- 继承是静态扩展(编译时确定),装饰器是动态扩展(运行时组合)。
- 装饰器 vs 代理:
- 代理控制访问,装饰器增强功能(代理通常只包装一层,装饰器可多层嵌套)。
七、总结
- 用装饰器当: 需动态扩展功能、避免破坏原有代码、组合数量未知时。
- 不用当: 功能扩展是静态的(直接继承)、或扩展会导致过度设计时。
记住这句话:装饰器是“即插即用”的功能扩展插件,用好它,代码更灵活、更干净!
相关文章
- Java接口安全:SpringBoot防护XSS/SQL/重放攻击
- Springboot之登录模块探索(含Token,验证码,网络安全等知识)
- JAVA装饰器模式适用场景,优缺点是什么你知道吗这篇文章彻底讲透
- TestNG 中使用 Guice 来进行依赖注入
- 测试开发之自动化篇-Appium脚本开发
- 深入探索FastAPI单元测试:使用TestClient轻松测试你的API
- python单元测试框架之unittest和pytest的区别
- 要供暖了,壁挂炉怎么调?注意这四点,省气还少出问题
- 掌握Python中的单元测试:详尽指南与unittest
- 《shell》算术表达式-test测试语句-if流程语句