代理模式之前在前端中都运用了很多,类中将某个功能需要某个类去实现,自己做不了需要代理为你做事;
tableview delegate,代理为他提供cell 为他提供高度,为他提供cell数量,没有提供话,tableview存在,但是不够健全。
代理深入一点理解就是将某个类进行功能增强。在原本逻辑前后增加一些逻辑,而调用者无感知。代理模式属于结构型 模式,有静态代理和动态代理。
静态代理:
代理为某个特定的类进行代理服务,不够灵活,若要进行功能修改,那么代理和被代理都需要代码修改,违背的开闭原则。最后还是以例子说话,就以买票例子,普通的人需要买票,可以找到买票代理买到符合想要的票,模型设计,首先设计一个接口,获取票的接口
public interface TicketInterface {
public void getTiket(HrTicket hrTicket);
}
票模型
public class HrTicket {
private String name;
private String price;
public HrTicket(String name, String price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
买票的人
public class NormalPerson extends Person implements TicketInterface{
private HrTicket hrTicket;
public void getTiket(HrTicket hrTicket) {
System.out.println("获得了某个票");
this.hrTicket = hrTicket;
}
}
静态代理:
创建一个人 有获得票的属性,为购票人提供符合要求的票
public class PersonProxyTicket extends Person implements TicketInterface{
public PersonProxyTicket(NormalPerson normalPerson) {
this.normalPerson = normalPerson;
}
private NormalPerson normalPerson;
public void getTiket(HrTicket hrTicket) {
System.out.println("查看该票是否符合客户要求");
System.out.println("符合客户要求---发票完成");
normalPerson.getTiket(hrTicket);
}
}
动态代理:
不需要关心代理对象是谁,为代理对象动态提供代理服务,首先我们使用jdk进行操作,将原理写在代码当中
public class DyPersonProxyTicket implements InvocationHandler {
private Object target;
public Object getInstance(Object object) throws Exception {
this.target = object;
Class> clazz = target.getClass();
//1.获取被代理类,拿到代理类和接口
//2.Proxy 通过反射机制拿到被代理类的所有方法和接口方法 进行代码重构重新生成新的代码类.class,里面重写的接口方法,
//3.将class文件重新加载到jvm里面进行运行
//整个过程叫字节码重组,是不是很高大上居然做了这么多的事一行代码
//JDK 中有一个规范,在 ClassPath 下只要是$开头的 class 文件一般都是自动生成的
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
//生成的新类对象的时候之前保存了当前代理对象,在调用相同名称的方法的时候,会调用invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("查看该票是否符合客户要求");
System.out.println("符合客户要求---发票完成");
//在新的类中找到了被代理对象,并且执行被代理对象的方法
Object object = method.invoke(this.target,args);
return object;
}
}
//调用通过反射机制响应找到
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
其实我们可以理解在运行时调用通过代码重组的方式,生成了一个全新的静态代理类。就是静态代理的升级版。
有一点需要注意的是我之前在设计类的时候没有添加接口,但是jdk是强制需要一个接口的,所以在设计的时候需要遵守整个规则。
如果用cglibe的话就不需要考虑接口的问题
采用cglib:
public class FsPersonProxyTicket implements MethodInterceptor {
public Object getInstance(Class> clazz) throws Exception{
//和jdk 的方式其实是基本一样的,但是生成class文件,代码重构组合的时候没有采用反射机制,
//重写了被代理类的所有方法,生成了三个class文件
//一个是被代理类FastClass 另个是代理类FastClass(这两个是在调用的时候才被创建),还有一个编译的时候就会生成一个继承被代理类的子类
/**代理类和被代理类各生成一个 Class,这个 Class 会为代 理类或被代理类的方法分配一个 index(int 类型)。
* 这个 index 当做一个入参,FastClass 就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,
* 所以调用效率比 JDK动态代理通过反射调用高
* 内部处理逻辑很复杂
* **/
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("查看该票是否符合客户要求");
System.out.println("符合客户要求---发票完成");
Object ob = methodProxy.invokeSuper(o,objects);
return ob;
}
}
最后:
1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。