设计模式-代理模式 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
代理执行结束>>>

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值