介绍
代理代理,就是找个中间人来做代理处理某件事。不过读了书后感觉挺坑的,说好的代理,只是暴露相对客户端来说,实际执行的,还是直接人,泪奔。不过它的目的不是帮你执行,而是代理控制对象的访问。这个模式是个编程好帮手,使用时候多多的,Android源码中,我们一直都有接触到到AMS的使用就用到了代理模式
UML
使用场景
- 如果无法或者不想直接访问某个对象
事例
爸爸要通知孩子做家务,和玩耍,但是对于爸爸不想直接叫动孩子,想通过妈妈来叫孩子做家务和玩耍,那么妈妈就是中间的代理对象,孩子就是被代理对象。
- 先看看静态代理方式
- 先定义任务接口
public interface DoHomeWork {
/**
* 做家务
*/
void doHomeWork();
/**
* 玩耍
*
* @param time 时间
*/
void play(int time);
}
- 代理对象与被代理对象需要实现相同的接口,定义妈妈和孩子
public class Child implements DoHomeWork {
@Override
public void doHomeWork() {
System.out.println("做家务了");
}
/**
* 玩耍
*/
@Override
public void play(int time) {
System.out.println("玩耍"+time+"小时");
}
}
public class Mather implements DoHomeWork {
private DoHomeWork child;
public Mather(DoHomeWork child) {
this.child = child;
}
@Override
public void doHomeWork() {
child.doHomeWork();
}
@Override
public void play(int time) {
child.play(time);
}
}
- 爸爸作为客户端来进行调用做家务
/*
* 静态代理
* 孩子要做家务。但是不像自己来操作,交由妈妈来代理操作,则妈妈持有孩子对象
*/
DoHomeWork child = new Child();
DoHomeWork mather = new Mather(child);
mather.doHomeWork();
最后的结果就是,爸爸通过妈妈让孩子做了家务
这种静态代理方式比较简单,而且需要将代理对象也给申明出来。
除了静态代理,另外还有一种为动态代理,因为执行的最后都是被代理对象来执行,就是也可以不需要显示的申明代理对象,动态创建代理对象方式,那么一起看看。
- 动态代理方式
- 创建实现了InvocationHandler的动态代理类,jdk里的动态代理类需要实现它
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 {
System.out.println("执行前");
System.out.println("执行的方法:method" + method+",参数:");
Object invoke = method.invoke(object, args);
System.out.println("执行后");
return invoke;
}
}
- 爸爸重新使用动态方式来叫孩子做家务和玩耍
/*
* 动态代理
*/
//创造被代理对象
DoHomeWork childDo = new Child();
//创造代理对象
InvocationHandler dynamicProxy = new DynamicProxy(childDo);
//获取被代理对象的classLoader
ClassLoader classLoader = dynamicProxy.getClass().getClassLoader();
//通常使用的是这种方式创建,jdk3之后就有的代理方式
/*
* 第一个参数 getClassLoader() ,这里使用dynamicProxy这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数interfaces,真实对象实现的接口,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的InvocationHandler这个对象上,后面执行就是靠它的invoke了
*/
DoHomeWork dynamic = (DoHomeWork) java.lang.reflect.Proxy.newProxyInstance(classLoader,
new Class[]{DoHomeWork.class}, dynamicProxy);
dynamic.doHomeWork();
dynamic.play(3);
输出:
执行前
执行的方法:methodpublic abstract void pattern.proxy.DoHomeWork.doHomeWork(),参数:
做家务了
执行后
执行前
执行的方法:methodpublic abstract void pattern.proxy.DoHomeWork.play(int),参数:
玩耍3小时
执行后
咱们使用的是newProxyInstance出来的代理对象去调用执行,这里可以看到执行的方法和参数与执行结果,这就是动态代理。
ps:Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,这里转成了成DoHomeWork,仅仅是因为生成的对象也实现了这个接口,看看第二个参数是传入接口组,也可以转换为其中实现了的任何一个接口。
总结:代理模式也是经常使用的结构型模式之一。它的思想似乎就是,不直接叫执行者去干,中间增加一个代理人,在这个代理人上就可以再做文章了,比如AOP也是基于动态代理来实现的,我们在编码过程中或多或少都会接触到它。