代理模式 (Proxy)
场景问题
问题案例
考虑这样一个实际的业务场景:你需要访问一个远程服务(如远程图片、视频、数据库等),但希望在访问前后增加权限校验、缓存、日志等功能。
不用模式的解决方案
实现简化版本
最直接的做法是客户端直接访问远程服务:
public class RealImage {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片:" + filename);
}
public void display() {
System.out.println("显示图片:" + filename);
}
}
public class Client {
public static void main(String[] args) {
RealImage image = new RealImage("test.jpg");
image.display();
}
}
有何问题
- 客户端无法控制访问权限、缓存、日志等。
- 直接访问真实对象,扩展性差。
- 真实对象可能很重,频繁创建浪费资源。
解决方案
代理模式的定义
为其他对象提供一种代理以控制对这个对象的访问。
应用代理模式的思路
- 定义统一接口,真实对象和代理对象都实现该接口。
- 代理对象持有真实对象的引用,负责控制访问。
- 客户端通过代理对象间接访问真实对象。
代理模式的结构
- Subject:抽象主题,定义统一接口。
- RealSubject:真实主题,实现实际业务。
- Proxy:代理主题,控制对真实主题的访问。
代理模式的实现
// 统一接口
public interface Image {
void display();
}
// 真实对象
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片:" + filename);
}
public void display() {
System.out.println("显示图片:" + filename);
}
}
// 代理对象
public class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
System.out.println("代理:权限校验、日志等");
realImage.display();
}
}
使用示例
public class Client {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
image.display();
image.display();
}
}
代理重写示例
示例结构
示例代码
见上文"代理模式的实现"部分。
模式讲解
代理模式的功能
- 控制对真实对象的访问。
- 可扩展权限校验、缓存、延迟加载、日志等功能。
- 降低客户端与真实对象的耦合。
实现成接口
- 抽象主题通常定义为接口或抽象类。
使用工厂方法
- 可结合工厂方法模式,统一创建代理对象。
切换产品簇
- 可用于切换不同类型的代理,如远程代理、安全代理、虚拟代理等。