设计模式之代理模式
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
解析这个定义:
- “替身”表明在客户端看来,代理类与被代理类是同一类别,对客户端来说看上去没什么区别,依然能够满足诉求。如此可以看出代理类与被代理类来自同一个超类。
- “控制对这个对象的访问”,能够控制访问,说明前提是能够访问,才能在访问之前做这个限制,即代理持有对真实对象的引用(或能创建它)。
当然可能会质疑,用继承的方式不是也能完成目标吗,用代理类去继承被代理类,然后重写方法,加入控制逻辑。但这违背了"组合优于继承"原则,代理类与被代理类强耦合。

1. 图片加载开销大(从磁盘或网络加载耗时),希望首次显示时才加载(延迟加载)。
2. 某些图片需要权限校验,只有授权用户才能查看。
3. 客户端代码应统一接口,无需关心是直接加载图片还是通过代理。
// 1. 抽象接口(Subject)
interface Image {
void display();
}
// 2. 真实对象(RealSubject)
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(); // 模拟耗时加载
}
private void loadFromDisk() {
System.out.println("Loading image: " + filename);
}
@Override
public void display() {
System.out.println("Displaying image: " + filename);
}
}
// 3. 代理(Proxy)
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
private String userRole; // 模拟用户权限
public ProxyImage(String filename, String userRole) {
this.filename = filename;
this.userRole = userRole;
}
@Override
public void display() {
// 权限校验
if (!userRole.equals("admin") {
System.out.println("Error: You don't have permission to view " + filename);
return;
}
// 延迟加载
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// 4. 客户端调用
public class Client {
public static void main(String[] args) {
// 普通用户尝试访问(被拒绝)
Image protectedImage = new ProxyImage("secret.jpg", "guest");
protectedImage.display(); // Output: Error: You don't have permission...
// 管理员访问(成功加载)
Image adminImage = new ProxyImage("profile.jpg", "admin");
adminImage.display(); // Output: Loading image... Displaying image...
}
}
代理模式和对象适配器模式的类图结构在静态上看几乎一模一样,但学习模式不要死盯着类图,重要的事每个模式的职责意图。
- 代理模式是"同一个接口,增强功能"。类比于明星经纪人(控制访问)。
- 适配器是"不同接口,转换适配"。类比于电源转换头(接口转换)。