👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
🎵 当你的天空突然下了大雨,那是我在为你炸乌云
一、入门
什么是装饰者模式?
装饰者模式(Decorator Pattern)是 Java 中常用的结构型设计模式,它能在不修改原有对象结构的前提下,动态地为对象添加额外的职责。
为什么要装饰者模式?
假设你正在开发一个电商系统,需要处理订单的 基础价格 和 多种附加服务(如快递加急、礼品包装、保价服务等),且这些附加服务可以任意组合。
下面是没有用装饰者模式的代码实现:
// 基础订单
class BasicOrder { /* 计算基础价格 */ }
// 各种组合继承(产生大量重复代码)
class BasicOrderWithExpress extends BasicOrder {} // 基础+快递
class BasicOrderWithGiftWrap extends BasicOrder {} // 基础+礼品
class BasicOrderWithExpressAndGiftWrap extends BasicOrder {} // 基础+快递+礼品
// ...更多组合(n种附加服务会产生2^n个子类!)
存在问题:
- 类数量指数级增长:3种附加服务需要7个子类,4种需要15个…
- 代码重复严重:每个子类都要重写价格计算方法
- 难以维护:新增一个附加服务(如保价),需要修改所有相关子类
- 无法动态组合:运行时不能灵活增减服务
怎样实现装饰者模式?
装饰者模式由以下构成:
- 组件接口(Component):定义核心功能的抽象。定义被装饰对象和装饰器的共同行为规范,声明核心业务方法(如价格计算、服务描述),确保装饰过程的透明性(客户端无需区分原始对象和装饰后的对象)
- 具体组件(ConcreteComponent):基础实现类。实现组件接口的基础功能,作为装饰过程的原始起点(最内层的被装饰对象),不应包含任何装饰逻辑
- 装饰器基类(Decorator):持有组件引用,实现组件接口
- 具体装饰器(ConcreteDecorator):添加具体增强功能
【案例】订单系统 - 改
组件接口:Order
接口
interface Order {
double calculatePrice();
String getDescription();
}
具体组件:基础订单,BasicOrder
类
class BasicOrder implements Order {
public double calculatePrice() { return 100.0; } // 基础价格100元
public String getDescription() { return "基础订单"; }
}
装饰器基类:OrderDecorator
类
// 装饰器基类(关键:实现相同接口)
abstract class OrderDecorator implements Order {
protected Order decoratedOrder;
public OrderDecorator(Order order) {
this.decoratedOrder = order;
}
// 默认直接转发给被装饰对象
public double calculatePrice() {
return decoratedOrder.calculatePrice();
}
public String getDescription() {
return decoratedOrder.getDescription();
}
}
具体装饰器:ExpressDecorator
类(快递加急)、GiftWrapDecorator
类(礼品包装)、InsuranceDecorator
类(保价服务)
// 具体装饰器:快递加急
class ExpressDecorator extends OrderDecorator {
public ExpressDecorator(Order order) {
super(order);
}
public double calculatePrice() {
return super.calculatePrice() + 25.0; // 加急费25元
}
public String getDescription() {
return super.getDescription() + " + 快递加急";
}
}
// 具体装饰器:礼品包装
class GiftWrapDecorator extends OrderDecorator {
public GiftWrapDecorator(Order order) {
super(order);
}
public double calculatePrice() {
return super.calculatePrice() + 15.0; // 包装费15元
}
public String getDescription() {
return super.getDescription() + " + 礼品包装";
}
}
// 具体装饰器:保价服务
class InsuranceDecorator extends OrderDecorator {
public InsuranceDecorator(Order order) {
super(order);
}
public double calculatePrice() {
return super.calculatePrice() + 30.0; // 保价费30元
}
public String getDescription() {
return super.getDescription() + " + 保价服务";
}
}
客户端使用
public class Client {
public static void main(String[] args) {
// 基础订单
Order order = new BasicOrder();
// 动态叠加服务(可任意组合)
order = new ExpressDecorator(order); // 加急
order = new GiftWrapDecorator(order); // 包装
order = new InsuranceDecorator(order); // 保价
System.out.println(order.getDescription());
// 输出:基础订单 + 快递加急 + 礼品包装 + 保价服务
System.out.println("总价:" + order.calculatePrice());
// 输出:总价:170.0
}
}
二、装饰者模式在框架源码中的实现
Java I/O 流体系(最经典实现)
InputStream in = new BufferedInputStream( // 具体装饰器
new FileInputStream( // 具体组件
new File("test.txt")));
源码中的实现:
组件接口(Component):InputStream
抽象类。
具体组件(ConcreteComponent):FileInputStream
类。
装饰器基类(Decorator):FilterInputStream
类。
具体装饰器(ConcreteDecorator):BufferedInputStream
类。
// 装饰器基类 FilterInputStream
public class FilterInputStream extends InputStream {
protected volatile InputStream in; // 持有被装饰对象
protected FilterInputStream(InputStream in) {
this.in = in;
}
// 默认转发所有方法到被装饰对象
public int read() throws IOException {
return in.read();
}
}
// 具体装饰器 BufferedInputStream
public class BufferedInputStream extends FilterInputStream {
private byte[] buf; // 新增缓冲区状态
public BufferedInputStream(InputStream in) {
super(in); // 必须传入被装饰对象
buf = new byte[8192];
}
// 增强的读取方法(实现缓冲机制)
public int read() throws IOException {
if (pos >= count) {
fill(); // 装饰器新增的核心逻辑
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
}
Spring 框架中的装饰者应用
这里说的比较简单,后续我学到Spring源码再补充😁
典型场景:事务缓存装饰器
// 装饰器基类实现
public class TransactionAwareCacheDecorator implements Cache {
private final Cache targetCache; // 被装饰的缓存对象
public TransactionAwareCacheDecorator(Cache targetCache) {
this.targetCache = targetCache;
}
// 在事务提交后才执行实际put操作
public void put(final Object key, final Object value) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
public void afterCommit() {
targetCache.put(key, value);
}
});
}
}
- 装饰器注册:通过
CacheManager
包装原始缓存 - 事务感知:延迟缓存操作到事务提交后
- 与代理模式结合:常通过 AOP 动态应用装饰器
三、总结
装饰者模式的优点
- 动态扩展功能
- 无需修改原有代码,运行时动态添加功能
- 案例:
Java I/O
流中,BufferedInputStream
动态为FileInputStream
添加缓冲功能
- 避免类爆炸
- 相比继承,装饰者模式通过组合实现功能扩展,避免子类数量指数级增长
- 案例:电商订单系统中,3种附加服务只需3个装饰类,而不是7个子类
- 符合开闭原则
- 对扩展开放:新增装饰器不影响现有代码
- 对修改封闭:无需修改组件接口和具体组件
- 案例:Spring 的
TransactionAwareCacheDecorator
扩展缓存功能,不影响原有缓存实现
- 灵活组合
- 装饰器可以任意组合,实现不同功能叠加
- 案例:Netty 的
ChannelPipeline
中,多个ChannelHandler
可以按需组合
- 透明性
- 客户端无需区分原始对象和装饰后的对象
- 案例:
Java Collections
的unmodifiableList
返回相同接口类型,对客户端透明
装饰者模式的缺点
- 复杂性增加
- 多层装饰可能导致调用链过长,增加调试和理解难度
- 案例:
Java I/O
流中,多层装饰(如缓冲+字符集转换)可能让调用栈变深
- 装饰顺序敏感
- 不同装饰顺序可能导致不同结果
- 案例:电商订单系统中,先加急再包装 vs 先包装再加急,价格计算可能不同
- 小对象增多
- 每个装饰器都是一个独立对象,可能增加内存开销
- 案例:Netty 中,每个 ChannelHandler 都是一个独立装饰器
- 接口膨胀
- 组件接口需要定义所有装饰器可能用到的方法
- 案例:Java I/O 中,
InputStream
需要定义所有可能的流操作方法
- 不适合静态配置
- 如果功能组合是固定的,装饰者模式可能不如直接继承简洁
- 案例:某些业务场景中,功能组合是固定的,直接继承更合适
装饰者模式的适用场景
- 动态功能扩展
- 需要运行时动态添加或撤销功能
- 案例:Java I/O 流、电商订单附加服务
- 避免子类爆炸
- 功能组合复杂,继承会导致子类数量激增
- 案例:游戏装备系统(武器+宝石+附魔)
- 透明增强
- 需要在不改变客户端代码的情况下增强功能
- 案例:Spring 的
TransactionAwareCacheDecorator
- 分层处理
- 需要将功能拆分为多个独立模块,按需组合
- 案例:Netty 的
ChannelPipeline
、Web 中间件(权限校验→日志记录→缓存处理)
- 兼容性处理
- 需要在不修改原有代码的情况下适配新功能
- 案例:Java Collections 的
checkedList
实现类型安全