马上过年了,抢票无望,上午刚买机票,明天回家 - - 提前祝各位春节快乐~
设计模式分为三种类型,共23种
- 创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
- 结构型模式:代理模式、装饰模式、外观模式、享元模式、桥接模式、组合模式、适配器模式
- 行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)、访问者模式
Look Here:在开始的开始,我们要知道代理模式也经常被称为委托模式,其主要作用是为其他对象提供一种代理,以控制这个对象的访问 > <
职责(角色)分析(括号内是我自己定义的),角色之间通过接口进行关联
- 被代理者(真实逻辑执行者)
- 代理者(结果传送者)
我在学习代理模式时,发现很多文章喜欢用委托律师打官司的案例讲解代理模式,却没有说明律师虽是我们的代理者,但是真正的事件执行者还是自身(委托者),我们并不会直接和法官进行交流,而是通过我们的律师(代理者)向法官陈述事件的实际执行结果。
优点
- 职责分明,各自执行各自的逻辑,可以用单一职责原则阐述
- 高扩展性,符合开闭原则,方便进行修改
- 降低系统耦合度
缺点
- 首先当然是比直接调用原始对象多了一个中间者,会让结构有点复杂,所以代理模式属于结构型模式
- 调用原始对象的方法要通过代理来调用,可能会造成请求处理速度变慢
错误方式
之所以展示这种错误的实现方式,意图的告诉大家,虽然最后执行的结果一样,但是这种实现完全和代理模式毫不相关 ~ 因为代理模式的意义是隐藏真实逻辑执行者,一切皆与代理者进行沟通,代理者会进行
示例说明 :拟Son为被代理者(委托者),拟Father为代理者,然后在MainActivity类进行使用
被代理者
package com.example.yongliu.agencypattern;
import android.util.Log;
/**
* author yongliu
* date 2017/12/23.
* desc:
*/
public class Son {
static void talk(){
Log.e("tag","我努力学习八国语言,终于问鼎全球");
}
}
代理者(有没有发现,这个所谓的代理者完全是多余的存在…)
package com.example.yongliu.agencypattern;
/**
* author yongliu
* date 2017/12/23.
* desc:
*/
public class Father {
public static void speak(){
Son.talk();
}
}
使用方式
mBtn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Father father = new Father();
father.speak();
}
});
错误总结 :虽然我们这里也获取到了最终的结果,但却是通过static的静态修饰作用,直接调取了被代理者的方法,在此已经暴露了真正的执行者!而没有达到代理中的保护原则!
正确的代理模式一般分为俩种,静态代理和动态代理
静态代理、动态代理区别
-
静态代理、动态代理在创建代理者的时间维度有所不同
- 静态代理的代理者一般我们在程序运行前已经创建,当程序运行时已经编译完成,代理类对应的class编译文件就已经存在了
- 动态代理的代理者一般是在程序运行后由JDK动态创建
-
动态代理减少了业务代理类的产生,以及对业务接口的依赖,降低了耦合,但是仅支持interface代理
-
静态代理的委托者是提前已知的,动态代理的委托者更多的是未知的,不过因为未知,所以也具体一定的灵活性
静态代理
思想解析:代理者与被代理者实现同一接口,被代理者进行方法的具体实现,代理者进行方法的封装,我们只需在成员方法内封装该接口的实参,通过接口的实参调用我们背后的代理者就好
抽象代理者
package com.example.yongliu.agencypattern;
/**
* author yongliu
* date 2018/2/5.
* desc:
*/
public interface JobContent {
void jobName();
}
被代理者
package com.example.yongliu.agencypattern;
import android.util.Log;
/**
* author yongliu
* date 2018/2/5.
* desc:被代理者
*/
public class AgencyRole implements JobContent{
@Override
public void jobName() {
Log.e("tag","我的内容是学习更多的东西,去改变世界,那么我的职业就是 “程序员”");
}
}
具体代理者
package com.example.yongliu.agencypattern;
/**
* author yongliu
* date 2018/2/5.
* desc:代理者
*/
public class JobRole implements JobContent {
public JobContent jobContent=null;
public JobRole(JobContent jobContent) {
this.jobContent = jobContent;
}
@Override
public void jobName() {
jobContent.jobName();
}
}
使用方式
mBtn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AgencyRole agencyRole = new AgencyRole();
JobRole jobRole = new JobRole(agencyRole);
jobRole.jobName();
}
});
动态代理
动态代理无需手动创建代理角色,我们只需实现动态处理器即可,真实代理者会在JDK运行时动态创建;关于原理的话,主要是通过反射动态的生成代理者对象,也就是说在写代码的时候根本不知道要代理谁,具体代理谁会在执行阶段决定 ~
被代理者(委托者)
package com.example.yongliu.agencypattern;
import android.util.Log;
/**
* author yongliu
* date 2018/2/5.
* desc:被代理者
*/
public class AgencyRole implements JobContent{
public JobContent jobContent=null;
@Override
public void jobName() {
Log.e("tag","我的内容是学习更多的东西,去改变世界,那么我的职业就是 “程序员”");
}
}
动态处理器(代理者)
package com.example.yongliu.agencypattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* author yongliu
* date 2018/2/27.
* desc:这里需要注意的是实现InvocationHandler接口,重写方法,通过对应的被代理者实现对应需求,这里的动态主要体现在接口
*/
public class DynamicAgency implements InvocationHandler {
private Object object;
public DynamicAgency(Object object) {
this.object = object;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//当然这里可以对方法名进行判断过滤 if(method.getName().equals("***"))
Object invoke = method.invoke(object, objects);
return invoke;
}
}
使用方式
//动态代理
mBtn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//被代理者
AgencyRole agencyRole = new AgencyRole();
//动态代理者
DynamicAgency agency = new DynamicAgency(agencyRole);
//反射
ClassLoader classLoader = agencyRole.getClass().getClassLoader();
//动态创建代理类,需要传入一个类加载器ClassLoader;一个你希望这个代理实现的接口列表,这里要代理JobContent接口(被代理类已实现的接口);
//和一个InvocationHandler的实现,也就是前面创建的agencyRole(被代理者实例)。
JobContent lawyer = (JobContent)Proxy.newProxyInstance(classLoader,new Class[]{JobContent.class},agency);
lawyer.jobName();
}
});
Proxy.newProxyInstance()参数说明
- ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
- Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
- InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
动态代理底层实现 - 具体步骤
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入;
强制代理
关于这点可以先不看,因为理解的不是很透彻,存在一些疑问,若以后用到会回头在进行阐述!
强制代理比较特殊,它是通过真实角色找到代理角色,我们还是修改一下上面的例子的
被代理者 :
package com.example.yongliu.agencypattern;
import android.util.Log;
/**
* author yongliu
* date 2018/2/5.
* desc:被代理者 ,强制代理在于当前实例是否存在,存在的话直接调取方法,若不存在则返回对应结果
*/
public class AgencyRole implements JobContent{
public JobContent jobContent=null;
@Override
public void jobName() {
Log.e("tag","我的内容是学习更多的东西,去改变世界,那么我的职业就是 “程序员”");
}
//强制代理
public JobContent getProxy(){
//1.这里是关键,创建了我们的代理者
this.jobContent=new JobRole(this);
return this.jobContent;
}
@Override
public void jobMoney() {
//2.判断代理存在与否
if(this.getProxy()!=null){
Log.e("tag","月薪 8888");
}else{
Log.e("tag","月薪 去找你的代理人要吧");
}
}
private boolean isProxy(){
if (this.jobContent == null){
return false;
}else {
return true;
}
}
}
使用方式
//强制代理
mBtn4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AgencyRole agencyRole = new AgencyRole();
agencyRole.jobMoney();
}
});
注意 :代理者可以进行多方代理,好比一个律师可以同时接多个case,在实现多个接口的同时,只要抛出不同的方法进行封装处理就可以!
扩展内容
以前看blog时,发现还有一种是CGLIB代理
,但是因为性能较低,所以很少有人提及,那篇blog中的作者是这么介绍的,CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理
静态代理和动态代理是从code方便进行分类的。这两个分类根据适用范围来分都可以分为下面几种 ~
- 远程代理:为某个对象在不同的内存地址空间提供局部代理,是系统Server部分隐藏,以便Client不用考虑Server的存在
- 虚拟代理:如果要创建一个资源消耗较大的对象,可以先用一个代理对象表示,在真正需要的时候才真正创建
- 保护代理:用代理对象控制对一个对象的访问,给不同的用户提供不同的访问权限
- 智能引用:在引用原始对象的时候附加额外操作,并对指向原始对象的引用增加引用计数
参考资料