探索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–滑动冲突的产生及其处理
本文已经deprecated,关于动态代理,请参见从狡猾的房产中介来看动态代理
版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl
代理模式简介
代理模式(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+"块钱");
}
}
现在,房东又去房屋中介公司挂靠自己的房子,到了那一看:原来熟悉的那个代理出去办事了,刚好不在。正准备走呢,中介公司的经理挺着啤酒肚走过来,笑嘻嘻地说:请问您是来办理业务的吗?来,请坐,我给你们引荐以为我们这里服务最好的一个房屋代理人员办理您的相关事宜
嗯哼,我们来看看这个代理是怎么卖掉房东的房子的:
/**
* 本文作者:谷哥的小弟
* 博客地址: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动态代理机制做进一步的认识和理解