基本概念
代理模式:是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理对象作为客户端和目标对象之间的中介,允许在不修改目标对象的情况下,添加额外的控制逻辑(如访问权限、延迟加载、日志记录,事务管理等)。
核心结构:
- 抽象主题(
Subject
):定义代理和真实对象的共同接口
- 真实主题(
Real Subject
):实际需要被代理的对象
- 代理主题(
Proxy
):持有真实主题的引用,控制对真实主题的访问
示例说明
场景:设计一个图片加载系统,需要对大尺寸图片实现延迟加载(只有在真正需要显示时才加载实际图片),避免初始加载时消耗过多资源。
- 图片显示接口
1 2 3 4 5 6 7
| 代码实现
public interface Image { void display(); }
|
- 真实主题:实际图片对象(加载大尺寸图片资源)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class RealImage implements Image { private String fileName; public RealImage(String fileName) { this.fileName = fileName; loadFromDisk(fileName); } private void loadFromDisk(String fileName) { System.out.println(“加载图片: “ + fileName); } @Override public void display() { System.out.println(“显示图片: “ + fileName); } }
|
- 代理主题:控制对真实图片的访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class ProxyImage implements Image { private String fileName; private RealImage realImage; public ProxyImage(String fileName) { this.fileName = fileName; } @Override public void display() { if (realImage == null) { realImage = new RealImage(fileName); } System.out.println(“代理前置操作:检查访问权限”); realImage.display(); System.out.println(“代理后置操作:记录访问日志”); } }
|
- 测试验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Test { public static void main(String[] args) { Image image = new ProxyImage(“largeImage.jpg”); System.out.println(“程序初始化,未加载真实图片”); image.display(); System.out.println(“\n第二次调用display,直接使用缓存的真实图片”); image.display(); } }
|
- 执行结果
1 2 3 4 5 6 7 8 9 10 11 12
| 程序初始化,未加载真实图片 代理前置操作:检查访问权限 加载图片: largeImage.jpg 显示图片: largeImage.jpg 代理后置操作:记录访问日志
第二次调用display,直接使用缓存的真实图片 代理前置操作:检查访问权限 显示图片: largeImage.jpg 代理后置操作:记录访问日志
|
使用代理模式创建代表对象。代表对象控制对另一个对象的访问,被代表的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
什么是对象代理控制访问呢?可以认为由代理对象控制被代理对象的访问,之所以需要控制,在某种意义上客户对象不知道如何使用被代理对象,这个时候代理对象可以做一些额外的处理,方便客户对象使用。
类图如下:

总结
优点
- 控制访问:可以在代理中添加权限控制、流量限制等逻辑
- 延迟加载:避免过早创建资源密集型对象(如示例中的大图片)
- 增强功能:在不修改目标对象的情况下,添加日志、缓存、事务等功能
- 保护目标对象:隐藏真实对象的细节,防止客户端直接访问敏感对象
缺点
- 增加复杂度:引入代理类后,系统中类的数量增加
- 性能开销:代理调用会带来额外的方法调用开销(但合理使用可优化性能,如延迟加载)
使用场景
- 动态代理:
java.lang.reflect.Proxy
用于创建接口的代理对象
- 远程方法调用(RMI):
java.rmi
包中使用代理封装远程对象的访问
- 懒加载集合:
java.util.Collections
中的某些包装类(如 LazyList)