设计模式 -- 代理模式

102 阅读2分钟

代理模式使用代理对象完成用户请求,屏蔽用户对真实对象的访问。现实世界的代理人被授权执行当事人的一些事宜,无需当事人出面,从第三方的角度看,似乎当事人并不存在,因为他只和代理人通信。而事实上代理人是要有当事人的授权,并且在核心问题上还需要请示当事人。

在软件设计中,使用代理模式的意图也很多,比如因为安全原因需要屏蔽客户端直接访问真实对象,或者在远程调用中需要使用代理类处理远程方法调用的技术细节 (如 RMI),也可能为了提升系统性能,对真实对象进行封装,从而达到延迟加载的目的。

写法

没有什么可写的,就是用一个代理类继承/实现接口从而内部包含真实对象.在客户端使用代理类.
需要注意的是我们通常使用接口,实现具体被代理对象和代理类以及客户端的解耦:
代理模式角色分为 4 种:
主题接口:定义代理类和真实主题的公共对外方法;
真实主题:真正实现业务逻辑的类;
代理类:用来代理和封装真实主题;
客户端: 使用代理类和主题接口完成一些工作。

使用场景

代理模式的重点是你可以通过代理实现什么.

延迟加载

假设系统启动时需要加载一个很大的资源,启动时间很长,这时我们把可以把实际加载资源的操作封进代理类, 由代理类实现延迟加载(不用不加载),外部客户端调用统一使用代理类.
比如一个例子:

public interface Image {
   void display();
}

public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}
public class ProxyImage implements Image{
 
   private RealImage realImage;
   private String fileName;
 
   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}


public class ProxyPatternDemo {
   
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
 
      // 图像将从磁盘加载
      image.display(); 
      System.out.println("");
      // 图像不需要从磁盘加载
      image.display();  
   }
}

附加处理

当调用真实的对象时,代理处理另外一些事。比如打印日志.

远程调用

RPC远程调用

安全代理

用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候

动态代理

上面我们主要演示了手写代码实现的静态代理,
实际java支持基于JDK/cglib的动态代理,两者有不同的特点.