浅谈代理模式
一、什么是代理
用例子来说理解起来总是简洁的:
- 比如你觉得上分太累了,但是又想上分,怎么办?请代练(代理).
- 医院挂号太麻烦?请黄牛(代理)帮我们挂号.
- 写出威胁社会安定的代码被请到警察局喝茶?请律师(代理)帮我们打官司.
借用某大佬的话来说,代理就是当前对象不愿意干、没法干的事委托给别的对象来做,而我们只要做好本分就行了。
二、简单的示例代码
1.静态代理
一个描述职能接口:
interface Work{
void sale();
}
售票员:
public class Saler implements Work{
@Override
public void sale(){
System.out.println("Sales of goods");
}
}
代理类:
public class Proxy implements Work{
private Work worker;
public Proxy(Work work){
this.worker = work;
}
@Override
public void sale(){
this.worker.sale();//被代理对象的方法
this.vip();
}
public void vip(){
System.out.println("VIP专享,优先处理!");
}
}
可以看出,代理类不仅可以处理被代理类能处理的事,而且可以在这个基础上对功能做扩展 。
静态代理的优势:
- 扩展性好
- 职责清晰
- 运行速度快,对于静态代理而言,在程序运行之前,代理类和被代理类的.class文件就已经存在了,因为安排的明明白白,所以运行起来的时候会比动态代理快。
静态代理的缺点:
- 可维护性低,由于代理类和被代理类都实现了同一个接口,如果接口发生了更改,那么被代理类和所有的代理类都要进行修改,比如接口新增一个方法,那么所有的代理类和被代理类都要重写这个方法,这无疑增加了巨大的工作量。
- 可重用性低,通过观察可以发现,代理类们的代码大体上其实是差不多的,但是由于个别的差异,导致我们不得不重新写一个新的代理类。
2、动态代理
动态代理解决了静态代理多个代理类对象的问题,动态创建的一个代理类,不需要像静态代理那样显式的写出来。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Classname CGLIB
* @Description TODO
* @Date 2019/10/2 13:20
* @Created by AppleTree
*/
interface Subject{
void action();
}
//被代理类
class RealSubject implements Subject{
@Override
public void action() {
System.out.println("Real Subject!");
}
}
//代理类
class ProxySubject implements InvocationHandler {
private Object object;
public Object getInstance(Object object){
//实例化被代理的对象
this.object = object;
//返回一个代理类对象
return Proxy.newProxyInstance(
object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理类自己的业务
System.out.println("VIP");
//被代理类的业务
Object res = method.invoke(this.object, args);
return res;
}
}
public class CGLIB{
public static void main(String[] args) {
//被代理对象
RealSubject realSubject = new RealSubject();
//代理类对象
ProxySubject proxySubject = new ProxySubject();
Subject subject = (Subject) proxySubject.getInstance(realSubject);
subject.action();
}
}
当我们上述方法创建的代理类对象进行方法调用的时候,都会转化为对invoke方法的调用,例如我们调用通过getNewInstance方法产生的代理类的action方法,这个action方法就会传入invoke中,然后转化成对invoke的调用(这里的invoke方法其实就相当于代理类的sell方法,但是它没有写死,而是你传入什么方法,我就调用这个方法,实现了动态调用,与被代理类完全分割开来,完成解耦)
动态代理的优点:
- 代码重用性强
- 代理类被代理类完全解耦
动态代理的缺点:
- 不够灵活:在所有的代理类在访问函数的时候,会转化为对invoke函数的调用,也就是说在invoke函数里面新增的功能(如例子中的前后增强功能),都会去执行,可是有些时候我们并不想去执行这些功能,这就不得不再去实现一个代理类了。