打开相册时,屏幕上可能有几十张图片。
要是每张大图都马上从磁盘读取,页面会做不少没必要的工作。用户可能只点开其中一张。
代理模式可以先派一个轻量对象顶着,需要时再找真实对象。

所有图片一起加载,太着急了
真实图片对象一创建就读取文件。相册里对象一多,没点开的图片也会加载。
我们想要的效果很简单:创建图片条目时先别加载,用户点显示时再加载。
先看关键 UML 图
ProxyImage 和 RealImage 都实现 Image。
客户端拿到的是代理对象,但调用方式和真实图片一样。代理内部会在合适的时机创建 RealImage。
先统一一个接口
public interface Image {
void display();
}
客户端只认 Image,不用改调用代码。
真实图片负责加载和显示
public class RealImage implements Image {
private final String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("从磁盘加载:" + fileName);
}
public void display() {
System.out.println("显示图片:" + fileName);
}
}
真正费事的加载动作,仍由 RealImage 完成。
代理先不创建真实图片
public class ProxyImage implements Image {
private final String fileName;
private RealImage realImage;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
构造 ProxyImage 时只记住文件名。直到 display() 被调用,真实图片才出现。
第一次加载,后面直接显示
Image image = new ProxyImage("dog.jpg");
image.display();
image.display();
输出:
从磁盘加载:dog.jpg
显示图片:dog.jpg
显示图片:dog.jpg
加载只发生一次,显示发生两次。青岛话说,第一回费点劲,后面就利索了。
代理和装饰器别混了
两者看起来都包着另一个对象,也常使用相同接口。
代理更关心访问时机、权限或缓存。装饰器更关心增加新能力。
看目的,比背类图好使。
啥时候适合用代理
图片延迟加载、权限检查、远程调用、本地缓存,都能见到代理的思路。
如果真实对象创建很轻,也没有访问控制需求,再包一层容易把代码写绕。
狗哥收个尾
代理模式的重点,是 让代理对象控制对真实对象的访问。
代理和真实对象使用同一个接口。客户端照常调用,代理决定何时创建、何时转交。
下一篇继续聊 责任链模式,看看一笔报销怎么一级一级往上审批。