Android 中设计模式 ----代理模式
2018-01-24 14:44
260 查看
来源:http://blog.csdn.net/shift_wwx/article/details/79150717
一、定义
所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式也称为委托模式。
代理模式分静态代理和动态代理。
二、代理模式的结构
在代理模式中的角色:
抽象对象角色:声明了目标对象和代理对象的共同接口(如android的AIDL),这样一来在任何可以使用目标对象的地方都可以使用代理对象。
目标对象角色:定义了代理对象所代表的目标对象。
代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
三、静态代理
静态代理是已知代理类(proxy)的代码和实现类代码(Real),根据上面的结构存在的代理方式。
来看个简单的例子:
上面的代理类和实现类都存在并参与编译,这就是静态代理模式。上面例子中代理类ProxyObject中存放实现类的对象,通过实现类的对象调用真正实现的接口。
四、动态代理
动态代理与静态代理是相反的,通过反射机制动态地生成代理者对象,也就是说在写代码的时候根本不知道要代理谁,具体代理谁会在执行阶段决定。
1、与静态代理对比
不需要为真是主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也是非常烦人的事,如果接口有变动,则真实主题和代理类都要修改,不利于系统维护;
使用一些动态代理的生成方法甚至可以在运行时指定代理类的执行逻辑,从而大大提升系统的灵活性。
2、JDK动态代理
Jdk的动态代理是基于接口的。现在想要为RealSubject这个类创建一个动态代理对象,Jdk主要会做一下工作:
获取RealSubject上的所有接口列表
确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
将对应的字节码转换为对于的class对象;
创建InvocationHandler实例handler,用来处理Proxy所有方法的调用;
Proxy的class对象以创建的handler对象为参数,实例化一个proxy对象
Jdk通过java.lang.reflect.Proxy包来支持动态代理,在Java中要创建一个代理对象,必须调用Proxy类的静态方法newProxyInstance,该方法的原型如下:
loader,表示类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是Java安全模型的一部分。可以使用null来使用默认的加载器;
interfaces,表示接口或对象的数组,它就是前述代理对象和真实对象都必须共有的父类或者接口;
handler,表示调用处理器,它必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作。
InvocationHandler之于Proxy,就如Runnable之于Thread。InvocationHandler接口中只有一个方法invoke,它的作用就跟Runnable中的run方法类似,定义了代理对象在执行真实对象的方法时所希望执行的动作。其原型如下:
其中:
proxy,表示执行这个方法的代理对象;
method,表示真实对象实际需要执行的方法(关于Method类参见Java的反射机制);
args,表示真实对象实际执行方法时所需的参数。
在实际的编程中,需要优先定义一个实现InvocationHandler接口的调用处理器对象,然后将它作为创建代理类实例的参数。(抑或在调用newProxyInstance方法时使用匿名内部类。)这样就得到了代理对象。
真实对象本身的实例化在调用处理器对象内部完成,实例化时需要的参数也应该及时传入调用处理器对象中。这样一来就完成了代理对象对真实对象的包装,而代理对象需要执行的额外操作也在invoke方法中处理。
其后,在客户端中,如果需要使用真实对象时,就可以用代理对象来替代它了(有时需要类型强制转化)。
例如(修改下Proxy代码),
测试代码:
结果为:
上面实现了动态代理,通过ProxyHandler 的newProxyInstance方法将RealObject传入,最终获取的AbstractObject的对象并通过此对象调用共有的接口operate(),最终会invoke到RealObject中的实现接口。
如果其中的 RealObject类的接口或者函数发生变化时,只要相对AbstractObject的接口不变,上面的调用部分的code是无需修改的。
五、其他分类
静态代理和动态代理是从code方面进行分类的。这两个分类根据适用范围来分都可以分为下面几种:
远程代理:为摸个对象在不同的内存地址空间提供局部代理,是系统Server部分隐藏,以便Client不用考虑Server的存在。
虚拟代理:如果要创建一个资源消耗较大的对象,可以先用一个代理对象表示,在真正需要的时候才真正创建。
保护代理:用代理对象控制对一个对象的访问,给不同的用户提供不同的访问权限。
智能引用:在引用原始对象的时候附加额外操作,并对指向原始对象的引用增加引用计数。
六、总结
代理模式使用非常广泛,从分类就能感觉出来,而且其他的设计模式中也会有代理模式的影子。
代理模式优点:
协调调用者和被调用者,降低系统耦合度。
用小对象代表大对象,减少系统资源消耗,提高系统运行速度,如虚拟代理。
控制用户对呗调用者的使用权限,如保护代理。
代理模式缺点:
首先当然是比直接调用原始对象多了一个中间者,会让结构有点复杂。
调用原始对象的方法要通过代理来调用,可能会造成请求处理速度变慢。
更多的设计模式看:Android中设计模式
一、定义
所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式也称为委托模式。
代理模式分静态代理和动态代理。
二、代理模式的结构
在代理模式中的角色:
抽象对象角色:声明了目标对象和代理对象的共同接口(如android的AIDL),这样一来在任何可以使用目标对象的地方都可以使用代理对象。
目标对象角色:定义了代理对象所代表的目标对象。
代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
三、静态代理
静态代理是已知代理类(proxy)的代码和实现类代码(Real),根据上面的结构存在的代理方式。
来看个简单的例子:
public abstract class AbstractObject { //操作 public abstract void operation(); } public class RealObject extends AbstractObject { @Override public void operation() { //一些操作 System.out.println("Real operation..."); } } public class ProxyObject extends AbstractObject{ RealObject realObject = new RealObject(); @Override public void operation() { //调用目标对象之前可以做相关操作 System.out.println("before..."); realObject.operation(); //调用目标对象之后可以做相关操作 System.out.println("after..."); } } public class Client { public static void main(String[] args) { // TODO Auto-generated method stub AbstractObject obj = new ProxyObject(); obj.operation(); } }
上面的代理类和实现类都存在并参与编译,这就是静态代理模式。上面例子中代理类ProxyObject中存放实现类的对象,通过实现类的对象调用真正实现的接口。
四、动态代理
动态代理与静态代理是相反的,通过反射机制动态地生成代理者对象,也就是说在写代码的时候根本不知道要代理谁,具体代理谁会在执行阶段决定。
1、与静态代理对比
不需要为真是主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也是非常烦人的事,如果接口有变动,则真实主题和代理类都要修改,不利于系统维护;
使用一些动态代理的生成方法甚至可以在运行时指定代理类的执行逻辑,从而大大提升系统的灵活性。
2、JDK动态代理
Jdk的动态代理是基于接口的。现在想要为RealSubject这个类创建一个动态代理对象,Jdk主要会做一下工作:
获取RealSubject上的所有接口列表
确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
将对应的字节码转换为对于的class对象;
创建InvocationHandler实例handler,用来处理Proxy所有方法的调用;
Proxy的class对象以创建的handler对象为参数,实例化一个proxy对象
Jdk通过java.lang.reflect.Proxy包来支持动态代理,在Java中要创建一个代理对象,必须调用Proxy类的静态方法newProxyInstance,该方法的原型如下:
Object Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException
loader,表示类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是Java安全模型的一部分。可以使用null来使用默认的加载器;
interfaces,表示接口或对象的数组,它就是前述代理对象和真实对象都必须共有的父类或者接口;
handler,表示调用处理器,它必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作。
InvocationHandler之于Proxy,就如Runnable之于Thread。InvocationHandler接口中只有一个方法invoke,它的作用就跟Runnable中的run方法类似,定义了代理对象在执行真实对象的方法时所希望执行的动作。其原型如下:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
其中:
proxy,表示执行这个方法的代理对象;
method,表示真实对象实际需要执行的方法(关于Method类参见Java的反射机制);
args,表示真实对象实际执行方法时所需的参数。
在实际的编程中,需要优先定义一个实现InvocationHandler接口的调用处理器对象,然后将它作为创建代理类实例的参数。(抑或在调用newProxyInstance方法时使用匿名内部类。)这样就得到了代理对象。
真实对象本身的实例化在调用处理器对象内部完成,实例化时需要的参数也应该及时传入调用处理器对象中。这样一来就完成了代理对象对真实对象的包装,而代理对象需要执行的额外操作也在invoke方法中处理。
其后,在客户端中,如果需要使用真实对象时,就可以用代理对象来替代它了(有时需要类型强制转化)。
例如(修改下Proxy代码),
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyHandler implements InvocationHandler { Object obj = null; public Object newProxyInstance(Object realObj){ this.obj = realObj; Class<?> classType = this.obj.getClass(); return Proxy.newProxyInstance(classType.getClassLoader(), classType.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.print("I'm Proxy, I'm invoking...");//加上打印 method.invoke(obj, args); System.out.println("invoke end!");//加上打印 return null; } }
测试代码:
AbstractObject object = (AbstractObject) new ProxyHandler().newProxyInstance(new RealObject()); object.operate();
结果为:
I'm Proxy, I'm invoking... Real operation... invoke end!
上面实现了动态代理,通过ProxyHandler 的newProxyInstance方法将RealObject传入,最终获取的AbstractObject的对象并通过此对象调用共有的接口operate(),最终会invoke到RealObject中的实现接口。
如果其中的 RealObject类的接口或者函数发生变化时,只要相对AbstractObject的接口不变,上面的调用部分的code是无需修改的。
五、其他分类
静态代理和动态代理是从code方面进行分类的。这两个分类根据适用范围来分都可以分为下面几种:
远程代理:为摸个对象在不同的内存地址空间提供局部代理,是系统Server部分隐藏,以便Client不用考虑Server的存在。
虚拟代理:如果要创建一个资源消耗较大的对象,可以先用一个代理对象表示,在真正需要的时候才真正创建。
保护代理:用代理对象控制对一个对象的访问,给不同的用户提供不同的访问权限。
智能引用:在引用原始对象的时候附加额外操作,并对指向原始对象的引用增加引用计数。
六、总结
代理模式使用非常广泛,从分类就能感觉出来,而且其他的设计模式中也会有代理模式的影子。
代理模式优点:
协调调用者和被调用者,降低系统耦合度。
用小对象代表大对象,减少系统资源消耗,提高系统运行速度,如虚拟代理。
控制用户对呗调用者的使用权限,如保护代理。
代理模式缺点:
首先当然是比直接调用原始对象多了一个中间者,会让结构有点复杂。
调用原始对象的方法要通过代理来调用,可能会造成请求处理速度变慢。
更多的设计模式看:Android中设计模式
相关文章推荐
- [设计模式]代理模式在android中的使用
- Android设计模式之动态代理,实现方法拦截功能
- Android 设计模式 之 代理模式
- Android开发中常用的设计模式 --- 动态代理模式
- Android设计模式之代理模式 Proxy
- Android 设计模式之代理模式
- Android与设计模式——代理(Proxy)模式
- Android 设计模式实战笔记 代理模式
- 跟着Android学设计模式:代理(proxy)
- 跟着Android学设计模式:代理(proxy)
- Android设计模式------代理模式
- android应用开发设计模式之代理模式
- Android设计模式之(17)----代理模式
- Android设计模式应用-代理模式
- Android设计模式之代理模式(Proxy Pattern)
- android设计模式之代理模式
- java/android 设计模式学习笔记(9)---代理模式
- Android设计模式之代理模式Proxy浅显易懂的详细说明
- Android设计模式-代理模式
- java/android 设计模式学习笔记(9)---代理模式