关闭

从狡猾的房产中介来看动态代理

标签: Java设计模式动态代理Proxy源码
2693人阅读 评论(7) 收藏 举报
分类:

探索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);
}

嗯哼,这个协议很简单,房东委托中介公司售卖自己的房子。

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

先来看房东:

/**
 * 本文作者:谷哥的小弟
 * 博客地址: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+"块钱");
    }

}

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

嗯哼,我们来看看这个这位被称为”服务最好的中介”是怎么卖掉房东的房子的:

package cn.com;

import java.lang.reflect.Proxy;

/**
 * 原创作者:谷哥的小弟
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
public class TestProxy02 {

    public static void main(String[] args) {
        TradeProtocol owner=new Owner();
        ClassLoader classLoader=owner.getClass().getClassLoader();
        Class<?>[] interfaces = owner.getClass().getInterfaces();
        //创建InvocationHandler
        HouseAgentInvocationHandler invocationHandler=new HouseAgentInvocationHandler(owner);
        //生成动态代理
        TradeProtocol tradeProtocol=(TradeProtocol) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        tradeProtocol.sellHouse(1000000);
    }

}

HouseAgentInvocationHandler 的实现如下:

package cn.com;

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

/**
 * 原创作者:谷哥的小弟 
 * 博客地址:http://blog.csdn.net/lfdfhl
 */
public class HouseAgentInvocationHandler implements InvocationHandler {
    private Object object;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Integer money=(Integer) args[0];
        System.out.println("我是中介,业主的房子我实际卖了"+money+"块钱");
        Object result=method.invoke(object, new Object[]{money/2});
        System.out.println("我是中介,这次交易我赚了不少钱!!!");
        return result;
    }
}

好了,所涉及到的代码就这么多。或许有一点看不懂,这也无妨,我们先看看运行的结果再作详细的解释。控制台输出信息如下:

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

哇哈,狡猾的中介把房子卖了100W却告诉房东只买了50W,自己狠狠地赚了一笔!这是怎么回事呢?不急,我们通过这两个示例来回顾一下卖房子的经过。

  • 第一个示例中,房东将房屋委托给一个自己熟知的中介人员售卖房产;中介卖了多少钱就给房东多少钱
  • 第二个示例中,房屋中介公司的经理临场(动态)地指定了一个中介人员为房东办理售卖房屋的相关事宜
  • 第二个示例中,中介对售卖的过程做了手脚。由此可见:动态代理可方便地对被代理类的方法进行某些处理。比如,在方法实际调用前做一些过滤或者拦截操作或者修改,在方法调用后做一些善后处理等。

好了,生活中的例子看完了,我们再回到工作中的代码,结合示例分析Java动态代理技术。


动态代理技术分析

在Java的动态代理机制中,有两个非常重要的不可或缺的东西:

  • InvocationHandler接口

  • Proxy类

先来瞅瞅InvocationHandler接口

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

这段官方文档的主要含义是:
每个动态代理类都必须要实现InvocationHandler接口,并且每个动态代理类的实例都关联到了一个handler。当我们通过代理调用被代理对象的方法时,该方法的调用会被转发至InvocationHandler接口的 invoke( )中进行处理,方法如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{}

该方法有三个输入参数,它们分别代表什么呢?

  • proxy:最终生成的代理
  • method:被代理对象正在执行的方法
  • args:被代理对象正在执行的方法的输入参数

这么说,或许有点摸不着头脑。没事,我们在HouseAgentInvocationHandler类的invoke( )方法开头加几句打印语句:

@Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy.getClass()="+proxy.getClass());
        System.out.println("method.getName()="+method.getName());
        for(Object object:args) {
            System.out.println("object.getClass()="+object.getClass());
        }
        ..............
    }

输出结果:

proxy.getClass()=class com.sun.proxy.$Proxy0
method.getName()=sellHouse
object.getClass()=class java.lang.Integer

嗯哼,看了InvocationHandler接口,再来瞅瞅Proxy类。

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

这段官方文档的主要含义是:
Proxy用于动态创建一个代理类及其实例。该类中我们常用 newProxyInstance( )方法:

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

该方法有三个输入参数,它们分别代表什么呢?

  • loader:加载动态代理类的ClassLoader,该输入参数通常为被代理类的类加载器
  • interfaces:动态代理类需要实现的接口,该输入参数通常为被代理类使用的接口
  • handler:动态代理对象在调用方法时与之关联的InvocationHandler

从这里我们可以看出: 动态代理与静态代理的原理是一样的,但是在动态代理中它没有具体的代理类而是通过Proxy在JVM运行时利用反射动态地生成了一个代理。在静态代理中,需要代理(中介)与被代理对象(房东)遵守同一份协议;其实在动态代理中也是非常类似的,只不过它换了一种方式罢了,这点从newProxyInstance( )方法的参数interfaces就能看出端倪:这些接口(interface)不就是静态代理中的协议么?也可以这么理解:动态代理对于协议的遵守发生在newProxyInstance( )时;并且动态代理可以对原来协议中的方法”做手脚”!

至此,我们再回过头来梳理一下动态代理示例及其相关技术:

  • 房东遵守房屋售卖协议
  • 动态地生成代理,在生成代理的过程中代理也遵守了房屋售卖协议
  • 代理在执行协议中的方法时(比如sellHouse( )),将该方法转发至与该代理密切相关的InvocationHandler中
  • 在InvocationHandler中可对协议中的方法(比如sellHouse( ))进行额外的附加的处理
  • 在InvocationHandler中利用反射调用协议中的方法(比如sellHouse( ))。其实,从这里也可以看出来:动态代理属于Java反射技术范畴;或许细心的人从导包语句中也有所发现:java.lang.reflect.InvocationHandler;嗯哼,InvocationHandler就在reflect包下

小感悟

很多刚开始做开发的童鞋喜欢拿着一本厚厚的设计模式在角落里默默地啃。学习的劲头很足,态度也很端正,配得上10086个赞。在此,我也想提醒一下小伙伴们:学习态度和努力程度固然非常重要,但是我们也要注意学习方法。抛开实际应用和业务逻辑单纯地看设计模式是很难理解其精髓的。我们不妨将设计模式和自己的实际工作结合起来学习,比如做Android开发的小伙伴可结合Android源码或者非常流行的第三方库来深入地研究设计模式,在此推荐一篇《Retrofit分析-漂亮的解耦套路》供大家学习参考


参考资料

6
0
查看评论

房屋中介管理系统

房屋中介公司需要对日常工作中涉及到的房屋、房主和租房顾客等各类数据进行有效地管理,以实现业务的自动化,提高运行效率的同时也能够降低人力成本。本设计主要针对房屋中介公司建立一个数据库应用系统。 1 需求分析 房屋中间管理系统主要的是: (1)房主能够发布房屋信息,并能够对房屋信息进行修改和删除;(...
  • liuruiqun
  • liuruiqun
  • 2016-07-29 13:17
  • 1228

从房产中介到程序员--80后张江男

一个80后程序员、张江男的成长史
  • zhouyongku
  • zhouyongku
  • 2015-03-18 17:07
  • 3133

房产中介如何利用微信朋友圈卖房子

如今越来越多的人做“微商”,“微商”是一个宽泛的词语,本质来说,就是用微信朋友圈作为宣传推广的渠道,让你的朋友或者陌生人了解你的产品和服务,那如何才能更有效的到达目的呢?其中有很多需要注意的地方。 那朋友圈呈现的内容和个人平常发的东西就不能一样,目标是要体现出你的专业性和值得信赖,作为购房者,肯定...
  • linguifa
  • linguifa
  • 2017-04-25 13:19
  • 2713

房产中介

现在的房产中介很难做。某房产中介为了 ¥500 元说自己“不守诚信,说话就是不算话”。      昨天租房,看了一处不错,价钱也算能承受,付完定金后今天去签合同。付定金时中介陈述转义如下: if (今天没能签合同) {  ...
  • DL88250
  • DL88250
  • 2010-05-10 23:02
  • 1805

一个房屋中介业务建模的实例分析

 一位名叫Midhael Yan的朋友给我发来一封信,信中谈到这样一个问题。我觉得很有代表性,因此公开发布到BLOG上。这位朋友的问题是这样的:一个租房中介准备提供一个网上中介服务系统,主要包括以下服务:给求租者发布求租信息,寻找房屋信息给出租者注册一个店面,在小店里发布出租房信息,也支持...
  • coffeewoo
  • coffeewoo
  • 2008-11-18 18:19
  • 6813

【bzoj1202】 HNOI2005狡猾的商人 并查集

真他妈是道好题。 不知道谁能想出来拿并查集这么扯的东西。 用并查集维护一下类似前缀和的东西,如果当前是[x,y],那么从x-1向y连一条边,v[x]表示s[x]-s[q]的值,s是前缀和,q是x所在联通块的根,如果当前的x和y是在一个联通块里,就直接查询v[y]-v[x],因为sum(x,y)=s[...
  • u012288458
  • u012288458
  • 2015-09-17 14:57
  • 873

解读房产中介的花言巧语

房产中介为了达成交易,可以脸不红心不跳地将一幢破屋夸得天花乱坠,这一点已是众所周知的秘密。而今,一位业界人士站出来,开腔披露房产宣传术语背后的真正含义:所谓的“舒适怡人的乡村住宅”即意味着房产不仅小,而且距离商店至少有20分钟的车程。 以下即是房产中介经常使用的表述以及它们的隐含意: 中介说:这...
  • priestmoon
  • priestmoon
  • 2013-06-08 07:48
  • 691

房产中介的陷阱(转)

房产中介陷阱,请大家进来讨论,希望大家以后注意 http://weifang.sdnews.com.cn/wflt/201205/t20120523_684687.html 如果你要在恒信买房子,你流露出不想买的想法后,几个人轮番上阵让你买房子,有点类似网警提示;让你签合同。大家注意一定不要签,...
  • thatluck
  • thatluck
  • 2017-06-20 19:26
  • 366

投诉房产中介的网站

投诉房产中介的网站 那次是通过北京友家正业房地产经纪有限公司租的房子,没到期呢就让我们搬出去。押金还不给退。没有办法,找的网上投诉的。还挺管用,没过几天就退了一些 。在此记录下网址,分享给大家。 http://www.bjjs.gov.cn/tabid/2207/Default.aspx ...
  • jadesuper6
  • jadesuper6
  • 2012-10-19 10:40
  • 620

从现在看未来,在未来看现在

这句话是东华云计算集团老大说的,在此借用作标题,因为觉得讲得非常到位,这是创业者需要拥有的眼界与视野,在铺天盖地的创业大潮中,我们很多时候都有些盲目,冲动大于理智,激情大于智慧,在红海的世界里拼个你死我活的,殊不知到头来极大可能镜花水月却是一场空,尽管如此,我们还是要不断地去尝试与坚持,这是创业者最...
  • harrymeng
  • harrymeng
  • 2015-08-09 07:32
  • 2143
    个人资料
    • 访问:1943534次
    • 积分:27792
    • 等级:
    • 排名:第234名
    • 原创:819篇
    • 转载:0篇
    • 译文:1篇
    • 评论:1296条
    博客专栏
    开发交流


    为方便大家学习和交流Android开发,建了个群,欢迎大家加入。

    QQ群: 183899857(已满)
    QQ群: 250468947(新开)

    文章分类