谷哥的小弟学后台(29)——动态代理


探索Android软键盘的疑难杂症
深入探讨Android异步精髓Handler
具体解释Android主流框架不可或缺的基石
站在源代码的肩膀上全解Scroller工作机制


Android多分辨率适配框架(1)— 核心基础
Android多分辨率适配框架(2)— 原理剖析
Android多分辨率适配框架(3)— 使用指南


自己定义View系列教程00–推翻自己和过往,重学自己定义View
自己定义View系列教程01–经常使用工具介绍
自己定义View系列教程02–onMeasure源代码详尽分析
自己定义View系列教程03–onLayout源代码详尽分析
自己定义View系列教程04–Draw源代码分析及事实上践
自己定义View系列教程05–演示样例分析
自己定义View系列教程06–具体解释View的Touch事件处理
自己定义View系列教程07–具体解释ViewGroup分发Touch事件
自己定义View系列教程08–滑动冲突的产生及其处理


版权声明


代理模式简单介绍

代理模式(Proxy Pattern)是面向对象中一种非经常见的设计模式。

事实上,不单是在软件开发领域。在我们的日常生活中对于代理也时常可见。

比方:房东要将自家的房租出售,于是到房地产中介公司找一个代理,由他来帮自己完毕销售房屋,签订合同等等事宜。

在此。就以该生活场景为蓝本介绍Java的代理模式。


静态代理

房东通过一纸协议将自己的房子挂靠在房屋中介;嗯哼,我们来一起瞅瞅这个房东和中介公司共同达成的协议:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public interface TradeProtocol {
    public void sellHouse(int money);
}

嗯哼,这个协议非常easy。房东托付中介公司售卖自己的房子。

既然是房东和房屋中介共同达成的协议,那么房东和中介都须要遵守该协议。

先来看房东:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class Owner implements TradeProtocol{

    @Override
    public void sellHouse(int money) {
        System.out.println("我是房主,我的房子卖了"+money+"块钱");
    }

}

再来看中介:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class HouseAgent implements TradeProtocol {
    private TradeProtocol mHouseProtocol;

    public HouseAgent(TradeProtocol houseProtocol){
        mHouseProtocol=houseProtocol;
    }
    @Override
    public void sellHouse(int money) {
        System.out.println("我是中介,业主的房子卖了"+money+"块钱");
        mHouseProtocol.sellHouse(money);
    }

}

请注意HouseAgent的实现

  • 在HouseAgent的构造方法中传入TradeProtocol的对象比方Owner
  • 在HouseAgent的sellHouse()中调用TradeProtocol的对象(比方Owner)的sellHouse()
  • 所以,HouseAgent售卖(sellHouse())房子,实际上是房东售卖了房屋

測试例如以下:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class Test {

    public static void main(String[] args) {
        Owner owner=new Owner();
        HouseAgent houseAgent=new HouseAgent(owner);
        houseAgent.sellHouse(10000*100);
    }

}

測试结果:

我是中介,业主的房子卖了1000000块钱
我是房主。 我的房子卖了 1000000块钱

在该静态代理中,房东将房屋的售卖交给了中介代理,中介将房屋出售后又把钱一分不少地交给了房东。

咦。这咋不正确呢?现实中有这样大公无私,视金钱如粪土的房屋中介么?没有!绝对没有!

那么,中介是怎么赚钱的呢?我们继续往下看


动态代理

与之前一样。房东和中介之间存有一纸协议:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public interface TradeProtocol {
    public void sellHouse(int money);
}

房东遵守该协议:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

public class Owner implements TradeProtocol{

    @Override
    public void sellHouse(int money) {
        System.out.println("我是房主,中介告诉我:房子卖了"+money+"块钱");
    }

}

如今。房东又去房屋中介公司挂靠自己的房子,到了那一看:原来熟悉的那个代理出去办事了,刚好不在。正准备走呢。中介公司的经理挺着啤酒肚走过来。笑嘻嘻地说:请问您是来办理业务的吗?来,请坐。我给你们引荐以为我们这里服务最好的一个房屋代理人员办理您的相关事宜

嗯哼,我们来看看这个代理是怎么卖掉房东的房子的:

/**
 * 本文作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
package cn.com;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
        TradeProtocol owner=new Owner();
        ClassLoader classLoader=owner.getClass().getClassLoader();
        Class<?>[] interfaces = owner.getClass().getInterfaces();
        TradeProtocol houseAgent=(TradeProtocol) Proxy.newProxyInstance(classLoader,interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
                Object object=null;
                System.out.println("我是中介。业主的房子我实际卖了"+args[0]+"块钱");
                object=method.invoke(owner, new Object[]{(Integer)args[0]/2});
                System.out.println("我是中介,这次交易我赚了不少钱呢");
                return object;
            }
        });
        houseAgent.sellHouse(10000*100);
    }

}

在该实现中由系统自己主动地为我们创建了一个代理Proxy.newProxyInstance()

结果例如以下:

我是中介。业主的房子我实际卖了1000000块钱
我是房主,中介告诉我:房子卖了500000块钱
我是中介。这次交易我赚了不少钱呢

哇哈。中介把房子卖了100W却告诉房东仅仅买了50W,自己狠狠地赚了一笔。

嗯哼。这个样例我们看完了。在此对比Test类分析动态代理的实现

  • 动态代理与静态模式的原理是一样的,仅仅是它没有具体的代理类而是通过Proxy在JVM执行时利用反射动态地生成了一个代理。
  • 请注意Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法的三个參数
    • ClassLoader:类载入器。传入和被代理类使用的同样的类载入器就可以
    • Class<?>[] interface:代理类要实现的接口。传入和被代理类使用的同样的接口就可以
    • InvocationHandler h:当通过代理对象调用一个方法的时候,该方法的调用会被转发至InvocationHandler接口的invoke()方法来执行具体的调用
  • 请注意invoke(Object proxy, Method method, Object[] args)方法的三个參数
    • Object proxy:代理对象的引用
    • Method method:当前调用的方法
    • Object[] args:当前调用的方法的输入參数
  • 由此可见:动态代理可方便地对托付类的方法进行某些处理。比方在方法实际调用前做一些过滤或者拦截操作。在方法调用后做一些善后处理等

后会有期

我们会在学习Spring框架时对Java动态代理机制做进一步的认识和理解

posted @ 2017-08-13 15:41  zhchoutai  阅读(145)  评论(0编辑  收藏  举报