一、前言
代理模式(Proxy Pattern),也称为委托模式,是一种常用的结构型设计模式。代理模式,在我们实际生活中也处处可见其例子,如:代理上网,海外代购,请律师打官司......
那么具体什么是代理模式呢?
一句话定义:为其他对象提供一种代理对象,已控制对这个对象的访问。
详细一点,即为其他对象提供代理,已控制对这个对象的访问,代理对象起到类似中介的作用,不设计功能服务,亦可增加额外服务。
二、代理模式的分类和实现方式
1、分类
远程代理:为一个位于不同地址空间的的对象提供一个本地的代理 。典型的设计有:C/S架构属于远程代理的缩影虚拟代理:如果要创建一个资源消耗较大的对象,可以先用一个代理对象表示,在真正需要的时候才真正创建。 。典型设计:经常我们看到很多APP在加载图片的时候,会先加载一个默认的图片,等真正的图片加载完了之后再显示出来,这样非常的友好。保护代理:控制用户的访问权限。典型设计:就像我们的公众号的文章留言功能,只有你这个用户关注了该公众号之后才能留言,否则你就只能浏览不能留言
2、实现方式
两种:静态代理和动态代理
三、UML图
Suject: 申明真实主题与代理的共同接口方法,既可以是个抽象类也可以是个接口(具有抽象方法)。
RealSubject: 委托类或者被代理类,真实对象,实现了抽象方法,由其执行具体的业务逻辑。
ProxySubject:持有一个对真实主题的引用,实现的接口方法中调用真实主题类中相应的方法执行,从而实现了代理。
Client:客户类通过代理类间接地调用了真实主题类中定义的方法。
四、静态代理例子
新建一个起诉类接口:Subject
public interface ILawsuit {
void submit();//提交申请
void burden();//进行举证
void defend();//开始辩护
void finish();//诉讼完成
}
真正的起诉者:RealSubject
public class Civilian implements ILawsuit {
@Override
public void submit() {
System.out.println("起诉");
}
@Override
public void burden() {
System.out.println("举证");
}
@Override
public void defend() {
System.out.println("辩护");
}
@Override
public void finish() {
System.out.println("胜诉");
}
}
律师:ProxySubject
public class Lawyer implements ILawsuit {
private ILawsuit civilian;
public Lawyer(ILawsuit civilian) {
this.civilian = civilian;
}
@Override
public void submit() {
civilian.submit();
}
@Override
public void burden() {
civilian.burden();
}
@Override
public void defend() {
civilian.defend();
}
@Override
public void finish() {
civilian.finish();
}
}
客户端调用,调用律师的方法,通过律师调用真正的su起诉者的方法。
public class Client {
public static void main(String[] args) {
ILawsuit civilian = new Civilian();
ILawsuit lawyer = new Lawyer(civilian);
lawyer.submit();
lawyer.burden();
lawyer.defend();
lawyer.finish();
}
}
五、动态代理例子
上面的例子是一种静态代理,代理者的代码时先生成写好,然后再对其进行编译,在代码运行前,代理类的class编译文件就已经存在了 。
动态代理是相反的,通过反射动态的生成代理者对象,更灵活!也就是说在写代码的时候根本不知道要代理谁,具体代理谁会在执行阶段决定。
Java提供了一个便捷的动态代理接口InvocationHandler,动态代理类只要实现这个接口就行:
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//当然这里可以对方法名进行判断过滤 if(method.getName().equals("***"))
Object result = method.invoke(object,args);
return result;
}
}
我们通过 invoke 方法来调用具体的真实的方法,object 是被代理类,method 是被代理类的方法,args 是方法的参数 。
客户端调用:
public class Main {
public static void main(String[] args) {
ILawsuit lawsuit = new Civilian();
DynamicProxy proxy = new DynamicProxy(lawsuit);
ClassLoader loader = lawsuit.getClass().getClassLoader();
//动态创建代理类,需要传入一个类加载器ClassLoader;一个你希望这个代理实现的接口列表,这里要代理ILawsuit接口;
//和一个InvocationHandler的实现,也就是前面创建的proxy。
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},proxy);
lawyer.submit();
lawyer.burden();
lawyer.defend();
lawyer.finish();
}
}
动态代理并不局限与代理一个接口的实现,可以根据运行时传入的接口,动态的生成代理类,然后通过Method的invoke方法来执行被代理类的真实方法。非常灵活。
动态代理的意义
在不改变原来目标方法功能的前提下,可以在代理中增强自己功能代码。
当一个项目中,有一个功能是其他人写好的,你可以使用,但是不能满足我的需求,我需要再增加点代码,这次就需要使用代理来进行代码的增强,而不用改原来的代码。
感谢,以上例子来自 -> Android设计模式(十七)-代理模式 - 简书
六、Android源码中的代理模式分析
Android源码中有不少的代理模式实现,比如源码里的ActivityManagerProxy代理类 ,其具体代理的是 ActivityManagerNative的子类 ActivityManagerService。ActivityManagerService 的功能是负责四大组件的启动/切换/调度、进程的管理/调度 。
ActivityManagerProxy
和ActivityManagerNative
都是实现IActivityManager
这个接口,IActivityManager
就是抽象主题了,ActivityManagerProxy
为代理类,而真实主题是ActivityManagerNative
,而实际上ActivityManagerNative
是个抽象类,真正的具体实现是在它的子类ActivityManagerService
中。
这里的代理实质是个远程代理,ActivityManagerProxy
与ActivityManagerService
是运行在不同的进程空间中的。