关于代理模式的解析
在说代理之前,先说一下反射。 什么是反射就不说了,我就说一下应用场景,因为反射不纠结其原理,那真的就是api的调用了,这里我只是做个笔记。反射在各大框架里面应用的很广泛,比如我们常用的Retrofit,其中有一个方法create(),我们需要传入自己申明的API接口。这里就是典型的反射应用场景,通过反射拿到我们的api类对象,再通过这个类对象找到对应的方法。再看看如下代码,应该有点儿体会吧,是不是你的代码里有些地方就可以用到这个。还想了解多一点的话,可以参考一下这个java高级特性—反射
Class dialog = Class.forName("com.***.BaseDialogFragment");
Field mHandler = dialog.getDeclaredField("mHandler");
mHandler.setAccessible(true);//允许访问私有对象
Class handlerClass = Class.forName(mHandler.getType().getName());
Method handlerMethod = handlerClass.getDeclaredMethod("removeCallbacksAndMessages", Object.class);
handlerMethod.setAccessible(true);
handlerMethod.invoke(mHandler.get(this), (Object) null);//指明是哪个对象调用removeCallbacksAndMessages的方法
LogUtil.e("This dialog has destroyed!");
何为代理模式
一句话,给目标对象提供一个代理对象,并由代理对象控制对目标对象的访问。来来看下面这个草图,是不是就有点儿意思了。代理模式又分为静态代理和动态代理,其实静态代理应用的不多(因为违反了开闭原则),动态代理才是主流。再往下看看代码,你就一目了然了。
为啥要用代理模式呢?因为代理模式十分符合java开发的封闭开放原则,避免大幅度修改原先的代码,只是在原有的基础上进行拓展。笼统的来说,就是下面俩点:
- 通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性
- 通过代理对象可以对原有的业务进行拓展
大家可以看看以这个类图,又是一目了然:
.
静态代理的相关用法
接口申明相关操作,代理对象和目标对象都实现这个接口,然后代理对象调用目标对象的方法,在目标对象的方法调用之前和调用之后可以进行拓展,我写了一个简单的demo ,可以参考一下:
/**
* @Author: Ryan
* @Date: 2020/6/11 16:04
* @Description: java类作用描述
*/
public interface Selling {
void sellSomething();
}
目标对象:
/**
* @Author: Ryan
* @Date: 2020/6/11 16:07
* @Description: 目标对象
*/
public class RealObject implements Selling {
@Override
public void sellSomething() {
System.out.println("一条18块的利群");
}
}
代理对象:
/**
* @Author: Ryan
* @Date: 2020/6/11 16:06
* @Description: 代理对象
*/
public class RyanObject implements Selling {
private Selling selling;
public RyanObject(Selling selling) {
this.selling = selling;
}//传入目标对象
//代理对象可以对目标对象进行的业务拓展
private void extraService1() {
System.out.println("喊你一声靓仔");
}
//代理对象可以对目标对象进行的业务拓展
private void extraService2() {
System.out.println("提供美女收银员的微信");
}
@Override
public void sellSomething() {
extraService1();
selling.sellSomething();
extraService2();
}
}
调用方法:
/**
* @Author: Ryan
* @Date: 2020/6/11 16:17
* @Description: 测试输出类
*/
public class TestClient {
public static void main(String[] args) {
/*-------------静态代理模式-------------*/
Selling selling = new RealObject();//实现接口的方法,
RyanObject ryanObject = new RyanObject(selling);//将目标对象的业务传给代理对象,同时代理对象内部可以对其做扩展
ryanObject.sellSomething();
/*-------------动 态代理模式-------------*/
}
}
总结:前面提到了今天代理违反了设计模式的开闭原则,这里解释一下。打个比方,现在又来了一个顾客他想买RIO鸡尾酒,代理对象是不是现在不能满足这个需求,是不是只有扩展目标对象,代理对象才可以有RIO卖,这样一来一共就那么几个文件,全得修改一遍,那要是人家想买一堆杂七杂八的,可想而知。。。。。
动态代理的相关用法
动态代理有俩个关键的字段,一个是proxy,一个是invocationHandler,前者你可以理解为是是通过这个proxy获取到动态代理对象,后者则可以理解成拓展的需求服务啥啥的。
动态生成代理对象:
/**
* @Author: Ryan
* @Date: 2020/6/11 17:36
* @Description: 动态生成代理对象
*/
public class ActiveRealObject implements InvocationHandler {
private Object realObject;
public Object getRealObject() {
return realObject;
}
public void setRealObject(Object realObject) {
this.realObject = realObject;
}
//代理对象的方法可以对目标对象进行的业务拓展
private void extraService1() {
System.out.println("喊你一声靓仔");
}
//代理对象的方法可以对目标对象进行的业务拓展
private void extraService2() {
System.out.println("提供美女收银员的微信");
}
public Object getProxyInstance() {//利用poxy通过反射获取到动态代理对象
return Proxy.newProxyInstance(realObject.getClass().getClassLoader(), realObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//这里就是对原先的业务拓展
extraService1();
Object object = method.invoke(realObject, args);//通过反射,调用了目标
extraService2();
return object;
}
}
调用方法:
/**
* @Author: Ryan
* @Date: 2020/6/11 16:17
* @Description: 测试输出类
*/
public class TestClient {
public static void main(String[] args) {
// /*-------------静态代理模式-------------*/
// Selling selling = new RealObject();//实现接口的方法,
// RyanObject ryanObject = new RyanObject(selling);//将目标对象的业务传给代理对象,同时代理对象内部可以对其做扩展
// ryanObject.sellSomething();
/*-------------动态代理模式-------------*/
Selling selling1 = new RealObject();
ActiveRealObject activeRealObject = new ActiveRealObject();
activeRealObject.setRealObject(selling1);//设置代理对象的代理目标
Selling proxy = (Selling) activeRealObject.getProxyInstance();
proxy.sellSomething();
Recycling recycling=new RealObject2();
ActiveRealObject activeRealObject2 = new ActiveRealObject();
activeRealObject2.setRealObject(recycling);//设置代理对象的代理目标
Recycling proxy2= (Recycling) activeRealObject2.getProxyInstance();
proxy2.recycleSomething();
}
}
总结:
- 接口申明需求
- 目标对象实现接口
- 实现iinvocationHandler接口,动态生成代理对象,生成代理对象过程中可以扩展需求
前俩步动态代理和静态代理是一致的,区别就在于第三步,很明显第三步能适应多样化的需求,拓展性更高,但是内部实现的时候用到了java的反射,所以动态代理的性能要逊色于静态代理的。。。。。先比比这么多,下班了!