设计模式-代理模式 Java示例

Posted Ruffian-痞子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-代理模式 Java示例相关的知识,希望对你有一定的参考价值。

代理模式定义:为其他对象提供一种代理,以控制对这个对象的访问。在某些情况下,对一个对象的访问或者引用存在困难时,通过代理对象起到连接客户端和目标对象的桥梁作用

这个定义还是挺清晰的,先不纠结什么是访问困难的情况,先了解如何通过一个代理对象连接 客户端(需要调用目标对象的地方)和 目标对象。等到实际开发中遇到访问存在困难的时候,自然就能想到使用代理模式解决,所以设计模式真的不是强行使用的,而是在某些特定情况下自然而就使用了

OK,现在模拟一个场景:代购

代购的场景大家都很常见了,比如小明想要买一部苹果笔记本MAC,只能到香港买,小明没有通行证,所以找代购。

1.静态代理

创建一个接口:购买需求

public interface IPurchase 
    /**
     * 购买MAC
     */
    void buyMac();

创建一个接口实现类,购买mac. 此处代表小明,他想要购买mac

public class PurchaseImpl implements IPurchase 
    @Override
    public void buyMac() 
        System.out.println("购买Mac");
    

由于小明无法直接购买,所以找了一个代理。创建一个代理购买类

public class PurchaseProxy implements IPurchase 
    //委托人(小明)
    private PurchaseImpl mPurchaseImpl;

    public PurchaseProxy(PurchaseImpl purchaseImpl) 
        mPurchaseImpl = purchaseImpl;
    

    @Override
    public void buyMac() 
        System.out.println("代理去香港...");
        //帮小明买mac
        mPurchaseImpl.buyMac();
    

代理类需要实现购买需求 implements IPurchase,帮谁购买?帮小明购买 public PurchaseProxy(PurchaseImpl purchaseImpl) 实现与小明挂钩,代理实现购买,但是他需要先到香港去,或者做一些其他操作,然后才是真正帮小明购买mac mPurchaseImpl.buyMac();

执行

public static void main(String args[]) 
        IPurchase purchase = new PurchaseProxy(new PurchaseImpl());
        purchase.buyMac();

输出结果

代理去香港…
购买Mac

嗯,代码很清晰,小明有购买需求,需要实现购买接口。代理帮小明购买,同样需要实现购买接口,同时代理可以做一些购买之外的事情,比如说去香港,或者收取代购费用,这些操作都是可以在代理类中实现

以上我们通过静态代理的模式,实现了代购帮小明购买mac的场景。但是我们发现,好像这个代购只能为小明服务,因为在构造函数中绑定了 PurchaseImpl 同时在 baymac() 也是使用这个对象的 baymac() 如果代购想多赚点钱,帮所有人购买mac呢?怎么实现?

2.动态代理

前面说了,代购不满足现状,想帮所有有需要的人购买mac,于是他改变了策略,他说我可以帮你们代购,无论是谁只要有需求,告诉我就行了。我就会帮你们买回来。这时候就需要用动态代理了

public class PurchaseProxy implements InvocationHandler 

    //委托人(任何人都可以)
    private Object mTargetObj;

    //创建代理(接受委托)
    public Object newProxyInstance(Object object) 
        this.mTargetObj = object;
        return Proxy.newProxyInstance(mTargetObj.getClass().getClassLoader(), mTargetObj.getClass().getInterfaces(), this);
    

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        System.out.print("代理去香港...帮>>>");
        Object temp = method.invoke(mTargetObj, args);
        return temp;
    

此时,小东,小刚…等等其他有需求的客人也想要购买mac

public class PurchaseImplXiaoD implements IPurchase 
    @Override
    public void buyMac() 
        System.out.println("小东购买Mac");
    
public class PurchaseImplXiaoG implements IPurchase 
    @Override
    public void buyMac() 
        System.out.println("小刚购买Mac");
    

执行代购

    public static void main(String args[]) 
        PurchaseProxy purchaseProxy = new PurchaseProxy();
        //帮小东代购
        IPurchase purchase = (IPurchase) purchaseProxy.newProxyInstance(new PurchaseImplXiaoD());
        purchase.buyMac();
        //帮小刚代购
        purchase = (IPurchase) purchaseProxy.newProxyInstance(new PurchaseImplXiaoG());
        purchase.buyMac();
    

输出结果:

代理去香港,帮>>>小东购买Mac
代理去香港,帮>>>小刚购买Mac

动态代理通过 Java 的反射机制,实现了动态绑定委托人(委托对象)

3.动态代理分析

Proxy.newProxyInstance() 方法

    /**
     *根据传入的目标返回一个代理对象
     *
     **/        
    //CLassLoader loader:类的加载器
    //Class<?> interfaces:得到全部的接口
    //InvocationHandler h:得到InvocationHandler接口的子类的实例
    Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

方法参数解释

    //该方法用于为代理指定类装载器、一组接口及调用处理器生成动态代理类实例  
    //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
    //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
    //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
    //返回值:根据传入的目标返回一个代理对象

使用

    //创建代理(接受委托)
    public Object newProxyInstance(Object object) 
        this.mTargetObj = object;
        return Proxy.newProxyInstance(mTargetObj.getClass().getClassLoader(), mTargetObj.getClass().getInterfaces(), this);
    

object 委托人(被代理对象)通过参数传入,

1.通过 mTargetObj.getClass().getClassLoader() 获取委托人的类加载器,传给代理对象 (代理对象和委托人需要同一个类加载器)
2.通过 mTargetObj.getClass().getInterfaces() 获取委托人实现的所有接口,传给代理对象 (代理对象和委托人需要实现一样的接口)
3.this 表示当前 InvocationHandler 对象(被拦截的方法需要执行当前 InvocationHandler 的 invoke 方法 )

然后返回一个代理对象。

InvocationHandler 接口

public interface InvocationHandler 

    //Object proxy : 被代理的对象(委托人)
    //Method method: 表示原对象被调用的方法
    //Object[] args: 方法调用时所需要参数
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

我们修改一下 buyMac() 方法添加参数,用于演示获取方法被调用时得到参数

public interface IPurchase 
    /**
     * 购买MAC
     * @param model  型号
     * @param number 数量
     */
    void buyMac(String model, int number);
public class PurchaseImpl implements IPurchase 
    @Override
    public void buyMac(String model, int number) 
        System.out.println("购买Mac. 型号:" + model + " 数量:" + number);
    
public class PurchaseProxy implements InvocationHandler 

    //委托人(任何人都可以)
    private Object mTargetObj;

    //创建代理(接受委托)
    public Object newProxyInstance(Object object) 
        this.mTargetObj = object;
        return Proxy.newProxyInstance(mTargetObj.getClass().getClassLoader(), mTargetObj.getClass().getInterfaces(), this);
    

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        System.out.println("start>>>   args==null?" + (args == null));
        if (args != null) 
            for (int i = 0; i < args.length; i++) 
                System.out.println("args:" + args[i]);
            
        
        //调用目标方法
        Object temp = method.invoke(mTargetObj, args);
        System.out.println("end>>>");
        return temp;
    
    public static void main(String args[]) 
        PurchaseProxy purchaseProxy = new PurchaseProxy();
        IPurchase purchase = (IPurchase) purchaseProxy.newProxyInstance(new PurchaseImpl());
        //型号:pro 数量:5
        purchase.buyMac("pro", 5);
    

args 参数数组表示 void buyMac(String model, int number); 方法的参数列表[String,int],如果 void buyMac(); 是没有参数的方法,那么 args 为 null . 看一下运行结果

代理执行开始>>>   args == null ?false
args:pro
args:5
购买Mac. 型号:pro 数量:5
代理执行结束>>>

以上便是对静态代理模式,动态代理模式的一点分析。讲完…

以上是关于设计模式-代理模式 Java示例的主要内容,如果未能解决你的问题,请参考以下文章

终于有人把 java代理 讲清楚了,万字详解!

Java设计模式之《代理模式》及应用场景

Objective-C中的委托(代理)模式

Java动态代理原理

Java设计模式学习06——静态代理与动态代理(转)

Java代理详解