代理模式也叫委托模式,是一种结构型的设计模式。代理不仅仅在编程世界,在日常生活中也是到处可见,比如车票代理、法律委托、游戏代理等等。代理模式在Java世界中也是随处可见,经常遇到的大致可以分为静态代理和动态代理两大类。
定义
为其他对象提供一种代理以控制对这个对象的访问
场景
- 当无法访问一个对象时
- 当访问一个对象有困难时
- 当不想将对象直接暴露出去时
- 当期望执行一些统一的附加操作时
角色
抽象主题(非必须)
主要是声明被代理对象的一些接口方法,可以是抽象类类型,也可以是接口类型
真实主题
被代理的真实对象,该对象一般无法被外部调用或者不想被外部调用。
代理对象
代理的对象,提供给外部调用,一般具有和真实对象一致的接口和方法。
分类
从代码的角度
静态代理
代理类由开发者或者开发工具在程序运行前就已经编码完成,程序运行过程中无法再对其进行修改。
优点是实现简单、逻辑清晰、易读性强。
缺点是灵活性较低,扩展性相对动态代理较低
动态代理
在程序运行期间动态的创建代理对象,Java中是通过反射来实现的。
优点是灵活性高,扩展性较强,不用创建额外的代理类文件。缺点是只能针对接口来进行动态代理。由于使用了反射,性能低于静态代理
从适用范围的角度
远程代理
为某个对象在不同的地址空间提供据不代理,是系统可以将服务端的细节隐藏。例如安卓中的AMS。
虚拟代理
使用一个代理对象来表示一个非常消耗资源的对象,只在需要时候进行创建
保护代理
使用代理来提供对原始对象的访问。将原始对象的访问权限缩小,保护原始对象
智能引用
在访问原始对象时,执行一些附加操作,并对指向原始对象的引用计数。
源码分析
静态代理
下面来介绍一种静态代理模式,我们想创建一种统一的点击监听器,实现在点击过程中,进行数据统计任务
/**
* 真实的对象
*/
public class RealClick {
public void onClick() {
System.out.println(" call real object click .");
}
}
下面,我么来创建一个代理类角色
/**
* 静态代理类角色
*/
public class ProxyClick {
private RealClick realClick;
public ProxyClick(RealClick realClick) {
this.realClick = realClick;
}
/**
* 代理类方法直接调用真实对象的对应方法
*/
public void onClick() {
// 执行附加操作
realClick.onClick();
}
}
实际调用时,是调用了代理类的onClick
方法
/**
* 模拟客户端
*/
public void main() {
RealClick rc = new RealClick();
ProxyClick pc = new ProxyClick(rc);
pc.onClick();
}
可以看出,上面代码其实是一种智能引用。通过一层包装,来执行一些附加操作
动态代理
在Java中,动态代理是通过Proxy类来实现的。主要是newProxyInstance
方法。该方法参数包括类加载器、被代理接口的Class
对象,以及一个用来接收方法调用的对象InvocationHandler
,该类是一个接口,只有一个方法invoke
,在动态地理过程中,真实方法的调用都会回调到InvocationHandler.invoke
方法。因此,invoke
是整个动态代理最终的出口,一般会在该方法中检测方法名等,来进行具体的业务处理。
Proxy
类注释中有这么一段话,明确指示了该类的作用。
* {@code 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.
在使用动态代理时,需要注意的是,动态代理只能够接收接口类型的真实对象。
总结
代理模式在Java和Android中应用非常广泛,并且他没有明显的缺点。他是细分到很小的一种设计模式。