代理模式(Proxy Pattern)和装饰器模式(Decorator Pattern)都属于结构型设计模式,它们在代码结构上看起来很相似——都是通过一个包装类来增强或控制对目标对象的访问。但它们的目的和使用场景有本质区别。
一、核心目的不同
| 模式 | 核心目的 |
|---|---|
| 代理模式 | 控制对目标对象的访问(例如:权限控制、延迟加载、日志记录等),强调“代表”另一个对象。 |
| 装饰器模式 | 动态地给对象添加职责/功能,强调“扩展”对象的行为,而不改变其接口。 |
二、典型应用场景
代理模式常见用途:
- 远程代理:代表远程对象(如 RMI、Web Service 客户端)。
- 虚拟代理:延迟初始化开销大的对象(如图片懒加载)。
- 保护代理:控制对敏感对象的访问权限。
- 智能引用代理:在访问对象时附加额外操作(如引用计数、日志)。
装饰器模式常见用途:
- 动态地为对象添加功能,比如:
###三、实现上的细微差别
虽然两者都持有被包装对象的引用并实现相同接口,但:
- 代理模式通常隐藏被代理对象的创建过程,客户端不知道真实对象的存在。
- 装饰器模式强调透明地扩展功能,多个装饰器可以链式叠加,且顺序可能影响行为。
// 示例:装饰器可叠加
Beverage coffee = new Coffee();
coffee = new Milk(coffee);
coffee = new Sugar(coffee); // 可继续包装
// 代理一般不叠加,且不暴露真实对象
Image image = new ProxyImage("photo.jpg"); // 内部才创建 RealImage
image.display(); // 代理控制何时加载真实图片
四、总结对比表
| 维度 | 代理模式 | 装饰器模式 |
|---|---|---|
| 意图 | 控制访问 | 动态添加职责 |
| 关注点 | 对象的访问控制 | 对象的功能增强 |
| 是否改变接口 | 否(保持一致) | 否(保持一致) |
| 是否可叠加 | 一般不叠加 | 支持多层嵌套装饰 |
| 创建时机 | 通常由代理负责创建真实对象 | 装饰器包装已存在的对象 |
| 耦合性 | 代理与真实对象通常紧耦合 | 装饰器与组件松耦合,可复用 |
类比理解
- 代理模式 ≈ 秘书:替老板(真实对象)接电话、过滤访客,你接触的是秘书,不是老板本人。
- 装饰器模式 ≈ 穿衣服:人(原始对象)穿上外套、帽子、围巾(装饰器),功能变多了,但还是同一个人。