模式定义
当客户类因为不适合、性能限制或者权限问题而无法(或性能较差)访问一种对象的时候,提供一种代理的机制,由代理来完成客户类的一系列请求。改代理能比较好地直接访问该对象。
使用方法
Proxy替Client来完成对RealSubject的直接访问。
使用范围
代理使用的范围比较多,如:
- 远程代理,适合远距离的对象传输或不在同一个地址空间内而比较耗时的对象访问
- 虚拟代理,当创建一个开销很大的对象时,可以使用该代理模式,使其只有当需要被创建或访问的时候才创建
- 保护代理,适合权限对某对象实施保护而客户类需要能访问其的时候
举例说明
此处,我们只举例虚拟代理的方式。假设需要在本地加载并显示一个图片,该图片十分庞大比较耗内存,那么可以短暂地先使改图片的占位符能显示在屏幕上,同时,启用另一个线程加载该图片:
public interface Image { public void displayImage(); } -------- public class RealImage implements Image{ private String filename; public void displayImage() { System.out.println("Display Real Image: " + filename); } public RealImage(String filename){ this.filename = filename; loadImageFromDisk(); } private void loadImageFromDisk(){ System.out.println("Loading Real Image: " + filename); } } -------- public class DummyImage implements Image{ private String filename; public void displayImage() { System.out.println("Display Dummy Image: " + filename); } public DummyImage(String filename){ this.filename = filename; loadDummyImage(); } private void loadDummyImage(){ System.out.println("Prepare Dummy Image: " + filename); } }
观察如上列出的两个实现Image的类。RealImage是实际加载图片的类,而DummyImage是实现占位功能的类,用来显示类似一个空白图片。
接下来需要创建Image的代理类。该类必须有如下功能:在RealImage还没有全部加载之前,启用DummyImage并返还给客户类,显示DummyImage。而当RealImage加载完成之后,则实际返回该类。
public class ProxyDisplay implements Image { private String filename; private Image img; private Image realImg; public ProxyDisplay(String filename){ this.filename = filename; } public void displayImage(){ if (img == null){ img = new DummyImage(filename); realImg = new RealImage(filename); //注 }else if (img instanceof DummyImage){ img = realImg; } img.displayImage(); } }
注意如上代码的注处:最好的实现方式是启用一个线程,同步加载。
最后客户类调用Proxy来加载图片。
public class ProxyClient { public static void main(String args[]){ ProxyDisplay pimg = new ProxyDisplay("hello.gif"); pimg.displayImage(); pimg.displayImage(); } }