意图
为其它对象提供一种代理以控制这个对象的访问。
结构
- Proxy保存一个引用使得代理可以访问实体;提供一个与Subject的接口相同的接口,使代理可以用来替代实体;控制实体的存取,并可能负责创建和删除它;其他功能依赖于代理的类型;
- Remote Proxy负责对请求及其他参数进行编码,冰箱不同地址空间中的实体发送已编码的请求;
- Virtual Proxy可以缓存实体的附加信息,以便延迟对它的访问;
- Protection Proxy检查调用者是否具有实现一个请求所必须的访问权限;
- Subject定义RealSubject和Proxy的公用接口,这样就可以在任何使用RealSubject的地方都可以使用Proxy。
- RealSubject定义Proxy所代表的实体。
适用性
Proxy模式适用于在需要比较通用和复杂的对象指针替代简单指针的时候,常见的情况有:
- 远程代理(Remote Proxy):为一个对象在不同地址空间提供局部代表。
- 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象。
- 保护代理(Protecion Proxy):控制对原始对象的访问,用于对象应该有不同的访问权限的时候。
- 智能引用(Smart Reference):取代了简单额指针,它在访问对象时执行一些附加操作,典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以被自动释放;当第一次引用一个持久对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。
代码示例
使用虚拟代理模式来设计图像查看器程序。将创建一个虚拟代理类 ImageProxy
和一个真实类 RealImage
。ImageProxy
类将延迟加载 RealImage
对象。
// 虚拟代理类
public class ImageProxy implements Image {private String filename;private RealImage realImage;public ImageProxy(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}realImage.display();}
}// 真实类
public class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;// 加载图像数据System.out.println("加载图像:" + filename);}@Overridepublic void display() {// 显示图像System.out.println("显示图像:" + filename);}
}// 测试代码
public class Main {public static void main(String[] args) {Image image1 = new ImageProxy("image1.jpg");Image image2 = new ImageProxy("image2.jpg");image1.display(); // 加载图像1image2.display(); // 加载图像2image1.display(); // 不再加载图像1}
}
代码设计注释
ImageProxy
类是一个虚拟代理类,它实现了Image
接口。ImageProxy
类有一个构造函数,它接受图像文件名作为参数。ImageProxy
类有一个display()
方法,它负责显示图像。如果realImage
对象为空,则创建一个新的RealImage
对象并加载图像数据。否则,直接调用realImage.display()
方法。RealImage
类是一个真实类,它也实现了Image
接口。RealImage
类有一个构造函数,它接受图像文件名作为参数。RealImage
类有一个display()
方法,它负责显示图像。- 在
Main
类中,创建了两个ImageProxy
对象,并调用了它们的display()
方法。第一次调用image1.display()
时,会加载图像1。第一次调用image2.display()
时,会加载图像2。第二次调用image1.display()
时,不会再加载图像1,因为realImage
对象已经存在