当前位置: 首页 > news >正文

Java设计模式之结构型—装饰器模式

装饰器模式(Decorator Pattern):不动原始类,动态给对象加功能
比继承更灵活,避免“子类爆炸”,是 Java IO 流、集合包装、Spring AOP 的底层思想。

下面用“一杯奶茶”+“源码”双重例子

生活例子:奶茶加料

基础奶茶 5¥+珍珠  +2¥+椰果  +1¥+奶盖  +3¥

用继承要写 8 个子类;用装饰器,运行时任意组合

UML 与角色

Component(接口)         Beverage└─ ConcreteComponent(基础实现) MilkyTeaDecorator(抽象装饰器)     ToppingDecorator├─ PearlTopping├─ CoconutTopping└─ CreamTopping

代码实现(奶茶)

// 1. 组件接口
interface Beverage {String desc();int cost();
}// 2. 基础实现
class MilkyTea implements Beverage {public String desc() { return "奶茶"; }public int cost() { return 5; }
}// 3. 装饰器骨架
abstract class ToppingDecorator implements Beverage {protected Beverage beverage;          // 持有被装饰对象ToppingDecorator(Beverage b) { this.beverage = b; }
}// 4. 具体装饰(可加任意多个)
class PearlTopping extends ToppingDecorator {PearlTopping(Beverage b) { super(b); }public String desc() { return beverage.desc() + " + 珍珠"; }public int cost() { return beverage.cost() + 2; }
}class CoconutTopping extends ToppingDecorator {CoconutTopping(Beverage b) { super(b); }public String desc() { return beverage.desc() + " + 椰果"; }public int cost() { return beverage.cost() + 1; }
}

客户端:任意组合

Beverage b = new MilkyTea();                    // 5¥
b = new PearlTopping(b);                        // +2¥
b = new CoconutTopping(b);                      // +1¥
System.out.println(b.desc() + " = " + b.cost()); // 奶茶 + 珍珠 + 椰果 = 8¥

运行期加料,一行代码一个功能,无需继承。

Java 标准库随处可见

IO 流

new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));

InputStreamReader 装饰 FileInputStreamBufferedReader 再装饰前者,逐层加功能。

集合

List<String> list = Collections.synchronizedList(new ArrayList<>());

synchronizedList 是装饰器,给 ArrayList 加同步。

优缺点一句话

优点缺点
比继承灵活,运行期任意组合会产生很多小类;调试略绕

背板口诀


装饰器,套娃皮,组合代替继承;Java IO 和同步集,层层包装加功能。

装饰器模式和代理模式区别

装饰器 = 功能增强(加法)
代理 = 控制访问(守门)

维度装饰器 Decorator代理 Proxy
目的给对象 添加/组合 新职责对对象 控制/约束 访问
接口必须实现 同一接口通常实现 同一接口
是否透明客户端察觉不到被装饰客户端知道代理存在
是否持有原对象,并递归调用原方法,但可拦截/不调用原方法
生命周期运行期动态组合编译/运行期固定代理
典型代码new BufferedReader(new FileReader())UserService proxy = new UserServiceProxy(real)
JDK 例子Java IO 流、Collections 同步包装RMI 远程代理、Spring AOP

生活例子对比

装饰器:给枪加消音器、瞄准镜

Gun gun = new AK47();
gun = new Silencer(gun);   // 增强:消音
gun = new Scope(gun);      // 再增强:瞄准
gun.shoot();               // 功能累加

代理:给枪加指纹锁(控制能否射击)

Gun real = new AK47();
Gun proxy = new FingerprintGunProxy(real);
proxy.shoot();             // 代理先校验指纹,再/或不再调 real.shoot()

代码级差异(同一接口 Gun)

// 装饰器:递归增强
class Silencer implements Gun {private Gun gun;public void shoot() {System.out.print("静音-");gun.shoot();        // 一定调原功能}
}// 代理:控制访问
class FingerprintGunProxy implements Gun {private Gun gun;public void shoot() {if (verifyFinger()) gun.shoot(); // 可拦截else System.out.println("拒绝射击");}
}

装饰加功能,代理做门卫;一个套娃增强,一个权限控制。

装饰器模式只有一层的情况下和代理模式几乎一摸一样?

是的,只有一层装饰且不改行为时,代码结构看起来跟代理几乎双胞胎:都实现同一接口、都持有原对象、都转发调用。
但**意图(purpose)**仍是分水岭:

  1. 目的不同

  • 装饰器:迟早要加新功能(哪怕现在没加,框架预留了“套娃”能力)。

  • 代理:要控制、屏蔽、扩展流程(权限、远程、懒加载、事务等)。

  1. 设计演进方向不同

  • 装饰器 → 支持多层嵌套、功能叠加(BufferedInputStream→LineNumberInputStream→...)。

  • 代理 → 通常固定一层,再套就没有“守门”意义了。

  1. 客户端感知

  • 装饰器:客户端主动套娃new Decorator(real),知道在叠加功能。

  • 代理:客户端只想拿到原接口即可,代理是透明的(Spring AOP、RPC stub)。

  1. 是否一定调用原方法

  • 装饰器:会调用,否则“增强”就断了。

  • 代理:可调用、可不调用(权限失败直接抛异常,不转给原对象)。

因此,单层且行为不变的代码确实像,但:

  • 未来是否叠加功能→装饰器

  • 是否要控制/隐藏原对象→代理

一句话:
结构像双胞胎,意图两条路;一层不增强,代理来守门;以后还想套,装饰留后手。


文章转载自:

http://RnUZWdqP.kzcfr.cn
http://eJUNcHDD.kzcfr.cn
http://7pw1M9Hy.kzcfr.cn
http://6pykxa3K.kzcfr.cn
http://J7na5Nwf.kzcfr.cn
http://DKeESXFh.kzcfr.cn
http://xodOCqGt.kzcfr.cn
http://Z4HHtbxw.kzcfr.cn
http://8cVr6nWW.kzcfr.cn
http://wIfuyZgW.kzcfr.cn
http://dcTOZGNw.kzcfr.cn
http://QnhxVFRj.kzcfr.cn
http://8IfXdkmq.kzcfr.cn
http://vQqZOAqX.kzcfr.cn
http://Zv9HUjmp.kzcfr.cn
http://2zdBt5D7.kzcfr.cn
http://OCojj9rL.kzcfr.cn
http://g7iZedZe.kzcfr.cn
http://b4Y1inw3.kzcfr.cn
http://nNMUmAcu.kzcfr.cn
http://mi5NomZ2.kzcfr.cn
http://MPiJqDMa.kzcfr.cn
http://dlG9wluB.kzcfr.cn
http://N0WE5oEi.kzcfr.cn
http://Fmtgk6Ok.kzcfr.cn
http://BRL51esy.kzcfr.cn
http://MN2HgHWQ.kzcfr.cn
http://yi8HzLEl.kzcfr.cn
http://5gKrWip4.kzcfr.cn
http://4hdRve9B.kzcfr.cn
http://www.dtcms.com/a/374139.html

相关文章:

  • Python编程基础(八) | 类
  • Ubuntu1804安装SonarQube
  • commons-lang3
  • 分布式专题——4 大厂生产级Redis高并发分布式锁实战
  • Infortrend普安科技IEC私有云平台VM解决方案
  • 实战对比:百炼知识库与钉钉知识库的全方位对比
  • GitLab升级后仓库镜像信任证书导入问题
  • 2. 计算机系统基础知识
  • 软考中级习题与解答——第三章_操作系统(2)
  • 第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛--算法题科普
  • 【CentOS7】使用yum安装出错,报HTTPS Error 404 - Not Found
  • 今天继续学习shell脚本
  • 解决哈希冲突
  • C++算法专题学习:栈相关的算法
  • CentOS部署ELK Stack完整指南
  • 多模态大模型Keye-VL-1.5发布!视频理解能力更强!
  • JAK/STAT信号通路全解析:核心分子、激活与负调控
  • 人工智能知识图谱应用平台国家标准发布实施
  • Chiplet封装革命:路登多芯片同步固晶治具支持异构集成
  • 语法分析:编译器中的“语法警察”
  • python数据分析工具特点分析
  • 高并发场景下的“命令执行”注入绕道记
  • Java创建对象的5种方式
  • Redis+Envoy实现智能流量治理:动态读写分离方案
  • ros2中qos的调优配置
  • 【GPT入门】第65课 vllm指定其他卡运行的方法,解决单卡CUDA不足的问题
  • 网络地址转换(NAT)详解
  • 综合体项目 3D 数字孪生可视化运维管理平台解决方案
  • 平衡车 -- MPU6050
  • 【PyTorch】图像二分类