Skip to main content

代理模式 (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();
}
}

有何问题​

  1. 客户端无法控制访问权限、缓存、日志等。
  2. 直接访问真实对象,扩展性差。
  3. 真实对象可能很重,频繁创建浪费资源。

解决方案​

代理模式的定义​

为其他对象提供一种代理以控制对这个对象的访问。

应用代理模式的思路​

  • 定义统一接口,真实对象和代理对象都实现该接口。
  • 代理对象持有真实对象的引用,负责控制访问。
  • 客户端通过代理对象间接访问真实对象。

代理模式的结构​

  • 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();
}
}

代理重写示例​

示例结构​


示例代码​

见上文"代理模式的实现"部分。


模式讲解​

代理模式的功能​

  • 控制对真实对象的访问。
  • 可扩展权限校验、缓存、延迟加载、日志等功能。
  • 降低客户端与真实对象的耦合。

实现成接口​

  • 抽象主题通常定义为接口或抽象类。

使用工厂方法​

  • 可结合工厂方法模式,统一创建代理对象。

切换产品簇​

  • 可用于切换不同类型的代理,如远程代理、安全代理、虚拟代理等。

执行时序图​