代理模式与动态代理——只是笔记,不是最好的讲解

之前了解过,后来又忘了。我想这应该就是没有理解吧。所以,我整理下要点,加深印象。

 

首先,代理的意思:我们在下载网络资源的时候(特别是国外资源,比如Android SDK的包),因为网速较慢,所以会选择走代理,这样能快点。所以代理的意思,就像它的字面意思一样,A想访问B的时候,由于某些原因,需要通过C来进行访问,C在这个场景里就充当了代理了角色。当然,这里有必要对【适配器模式】和【装饰器模式】进行区分。1、适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口;2、装饰器模式为了增强功能,而代理模式是为了加以控制

 

其次,代理模式(静态)的代码实现:在真实对象和代理之间抽出一个接口(真实对象和代理类都实现了该接口),代理类中包含了真实对象实例。这样当请求代理中的方法时(即接口中定义的那些方法),代理就可以调用真实对象的点该方法了(.display())

代码实例如下:

//1.接口文件定义
public interface Image {
   void display();
}
//2.定义实体类文件
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);
   }
}
//3.定义代理类的文件
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();        //毕竟只是代理,还是要调真正实体类的相应方法
    //依然可以加些自己的处理
   }
}
//4.使用代理模式的文件定义
public class ProxyPatternDemo {
   
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");    //创建代理
      // 图像将从磁盘加载
      image.display();     //因为代理类中的实体对象,刚开始是空的,所以加调用构造函数
      System.out.println("");
      // 图像不需要从磁盘加载
      image.display();  
   }
}

通过文件4的注释可以比较容易的分析出打印结果,如下:

Loading test_10mb.jpg
Displaying test_10mb.jpg

Displaying test_10mb.jpg

此时的代理模式实现似乎可以为我们提供点帮助。比如,我们想在display()之前之后做点什么。但随着实体类和代理类的增加,其代理模式就出现类的个数增加的问题,显然,需要了解下动态代理。而且这也是Java框架Spring的核心思想之一:IOC注解注入;AOP切面编程。

 

接着动态代理,JDK提供了两个类: java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。后者为接口,只包含一个函数:invoke(Object proxy, Method method, Object[] args)

第一个参数为:方法被调用的代理实例;第二个参数为:调用的方法;第三个参数为:调用方法的参数。

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

第一个参数:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载。既然是代理对象,自然是实现了InvocationHandler这个接口的类;

第二个参数:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了。既然是需要代理的对象,自然是真实对象所包含的方法了。真实对象才需要代理嘛。

第三个参数:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。显然是实现了InvocationHandler接口的类的对象。

紧接着上面的代码,我们编写动态代理的代码:

//3.动态代理的文件定义
public class DynamicProxy implements InvocationHandler{
    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log.e("proxy","before rent house");
        Log.e("proxy","Method:" + method);
        method.invoke(object,args);
        Log.e("proxy","after rent house");

        return null;
    }
}

调用时的代码:

//4.调用文件的代码定义
public static void test() {
        Image realImage = new RealImage("migu.cn");
        InvocationHandler handler = new DynamicProxy(realImage);
        Image proxyImage = (Image)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realImage.getClass().getInterfaces(),handler);
        proxyImage.display();
        proxyImage.hello("testmigusdk.network.proxy");
    }

最后,参考文献:

http://www.runoob.com/design-pattern/proxy-pattern.html

https://www.cnblogs.com/xiaoluo501395377/p/3383130.html

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值