设计模式之代理模式

一静态代理

    在一个商场里,小王和小李是同事,他们有着一样的工作,使用计算能力计算商品的每天的收益情况,但是他们有一点不同的是,小王计算牙刷的收益,小李计算袜子的收益,有一天小王生病了,让小李去帮他计算一下今天牙刷的收益情况! 这个时候我们怎么使用面对对象的思想来实现这一个逻辑呢。

    我们来分析一下 小王和小李都有一样的能力,计算的能力,根据依赖倒置原则(抽象不应该依赖细节,细节应该依赖抽象,说的直白点就是面向接口编程计算的能力)和里氏替换原则我们可以把他们两个拥有的相同的能力拿出来做成一个接口,然后让他们具体的类去实现它。

public interface Operate {

public void getResult();

}

小王和小李都有这种能力,小王请小李帮忙计算牙刷的收益,那么我们也可以这么理解小王确实需要帮忙,我们称作为真实对象,小李是被小王请来干活的,我们称作为代理对象。

那么小王这个类的功能是这样的:

public class RealObj implements Operate{
public void getResult() {
System.out.println("-------计算今天牙刷的收益------------");
}

}

小李类是这样的

public class ProxObj implements Operate{
RealObj  realObj=null;
public ProxObj(RealObj realObj){
this.realObj=realObj;
}
public void getResult() {//这里本来应该是小李计算袜子的收益,但是被请来帮忙小王计算牙刷的收益,所以得使用牙刷的运算方式,即调用小王的getResult()方法
realObj.getResult();

}

}

二静态代理

  本文主要说一下jdk中的代理模式如何实现,以及动态代理如何调用真实对象的方法 

 小王作为商场的优秀员工和一位好心的大哥,每次人家一有事就会去帮忙,但是每次帮忙的对象不同,帮忙要干的事情也不同,这个时候怎么办?其实大家看一下不管帮谁的忙,帮助的对象都是人类,我们定义为Object,帮忙干啥事也由被帮忙的对象说的算,我们可以用反射机制来实现。这样我们只需要定义一下小王有一个帮人忙的方法,小王只需要实现InvocationHandler这个类就行,大家很好奇为啥要在这里使用InvocationHandler,我的理解是:因为代理的类是用InvocationHandler实例化类的即实例化ProxObj ,这样做的好处就是不管什么样的代理类都需要被实例化,但是他们的类型通过这种方式我能确定下来,这样就好实例化,我会在后面讲到 所以修改的代码如下

public class ProxObj implements InvocationHandler{
Object  obj=null;
public ProxObj(Object obj){
this.obj=obj;
}
public Object invoke(Object ProxObj, Method method,
Object[] args) throws Throwable {
method.invoke(obj, args);//通过反射机制执行不同的 方法,这样能实现不管什么样的忙 不管谁的忙都能帮
return null;
}

客户端是这样的

       RealObj r= new RealObj();
             
         InvocationHandler hande= new ProxObj(r);
        Operate2  op2=(Operate2) Proxy.newProxyInstance(r.getClass().getClassLoader(), r.getClass().getInterfaces(), hande);

        op2.getResult();

好了这就是一个简单的动态代理模式

三 解读一下jdk的代理模式如何调用具体的方法

  看客户端的代码,我开始是完全不能理解的,我想客户端为既有InvocationHandler 又有Proxy,还有newProxyInstance,又用到类的加载器,接口等,我开始也不能理解,后来看了jdk的源码有一定的理解,先说说 InvocationHandler hande= new ProxObj(r);这里就是我刚刚讲的实现InvocationHandler 的好处,不管是什么类我都能这么实例化,还不仅仅如此,下面看到源码的时候会提,为啥使用Proxy,因为生产的代理类 继承了Proxy,而newProxyInstance()这个方法是关键:

 public static Object newProxyInstance(ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler)

    throws IllegalArgumentException

  {

   Class localClass = getProxyClass0(paramClassLoader, arrayOfClass);//其他的都省略了,这里localClass就是Proxy0,

   Constructor localConstructor = localClass.getConstructor(constructorParams);


   return localConstructor.newInstance(new Object[] { paramInvocationHandler });//标记1

  }

标记1出是通过创建的Proxy0类的构造器调用super方法给父类Proxy 中的InvocationHandler h=null赋值

源码这样的  

public class Proxy{

  public class Proxyprotected InvocationHandler h;

protected Proxy(InvocationHandler paramInvocationHandler)

  {
  
    h = paramInvocationHandler;

  }

}

newProxyInstance()方法里面有一个方法很关键 Class localClass = getProxyClass0(paramClassLoader, arrayOfClass);

而在getProxyClass0还有一个方法也很关键,

  Object localObject3 = ProxyGenerator.generateProxyClass(str1, paramArrayOfClass, ???);这个方法的作用就是通过加载器和接口 创建代理类Proxy0实现了真实对象的接口,并继承了Proxy类. 

下面是我写的一个调用generateProxyClass 的例子然后通过反编译

    private static String DEFAULT_CLASS_NAME = "$Proxy";
    
    public static byte [] saveGenerateProxyClass(String path,Class<?> [] interfaces) {  
   
        byte[] classFile = ProxyGenerator.generateProxyClass(DEFAULT_CLASS_NAME, interfaces);  
          
        FileOutputStream out = null;  
          
        try {  
            String filePath = path + "/" + DEFAULT_CLASS_NAME + ".class";
            out = new FileOutputStream(filePath);  
            out.write(classFile);  
            out.flush();  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                if(out != null) out.close();  
            } catch (Exception e) {  
                //ignore 
            }  
        }  
        return classFile;
    }  
    
    public static void main(String[] args) {
    Class<?> interfaces [] = {Operate.class};

    byte[] classFile =saveGenerateProxyClass("E:/", interfaces);  

}

生成的Proxy0文件 ,通过反编译 以后得到源码

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import ogryilai.Operate;


public final class $Proxy extends Proxy
  implements Operate
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;


  public $Proxy(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }


  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }


  public final void getResult()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);//这里就是实现动态代理,调用ProxObj的invoke方法
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }


  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }


  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }


  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("ogryilai.Operate").getMethod("getResult", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
    }
    throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
  }
}

看完了源码是不是对刚刚为啥使用那些参数和方法有一点的了解了,因为在创建Proxy0 的是会用到,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值