基本概念

代理模式:是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理对象作为客户端和目标对象之间的中介,允许在不修改目标对象的情况下,添加额外的控制逻辑(如访问权限、延迟加载、日志记录,事务管理等)。

核心结构

  1. 抽象主题(Subject):定义代理和真实对象的共同接口
  2. 真实主题(Real Subject):实际需要被代理的对象
  3. 代理主题(Proxy):持有真实主题的引用,控制对真实主题的访问

示例说明

场景:设计一个图片加载系统,需要对大尺寸图片实现延迟加载(只有在真正需要显示时才加载实际图片),避免初始加载时消耗过多资源。

  1. 图片显示接口
1
2
3
4
5
6
7

代码实现
// 抽象主题:定义图片显示接口
public interface Image {
void display();
}

  1. 真实主题:实际图片对象(加载大尺寸图片资源)
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. 代理主题:控制对真实图片的访问
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. 测试验证
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(“程序初始化,未加载真实图片”);
// 第一次调用display时,代理会创建真实图片对象
image.display();

System.out.println(“\n第二次调用display,直接使用缓存的真实图片”);
image.display(); // 真实图片已加载,直接使用
}
}

  1. 执行结果
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)