对码当歌,猿生几何?

基于JAVA的设计模式之代理模式

概念

    王宝强有一个经纪人叫宋喆,这个经纪人很吊,可以代理王宝强做一系列的事情,与粉丝活动、王宝强的微博维护、安排王宝强的行程以及什么什么等等。如果王宝强一个人做岂不是累死。通过这个代理人为王宝强节省了不少。

    代理模式就是在不改变原有类的代码结构上为类拓展新的功能。

  • 类图:subject为一个抽象的目标接口,客户端梦想的接口,realSubject为原始类,proxy为代理对象

  

  • 静态代理

//原类与代理类的公共接口public interface Subject {public void request();
}public class RealSubject implements Subject{public void request() {
        System.out.println("王宝强拍电影");
    }
}public class Proxy implements Subject {private Subject realSubject;public void setRealSubject(Subject realSubject) {this.realSubject = realSubject;
    }public void request() {
        System.out.println("宋喆代替王宝强维护微博");
        realSubject.request();
        System.out.println("宋喆代替王宝强与粉丝互动");
    }
}public class Main {public static void main(String[] args) {
        Subject realSubject=new RealSubject();
        Proxy proxy=new Proxy();
        proxy.setRealSubject(realSubject);
        proxy.request();
    }
}
  • 动态代理

public interface Subject {public void request();
}public class RealSubject implements Subject {public void request() {
        System.out.println("王宝强拍电影");
    }
}public class ProxyMain {public static void main(String[] args) {final RealSubject realSubject=new RealSubject();
        Subject proxy=(Subject) Proxy.newProxyInstance(/** * ClassLoader 被代理类的加载器
                 * Interfaces 代理对象与被代理对象公共接口
                 * InvocationHandle 事件处理                 */realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
                        System.out.println("宋喆代替王宝强维护微博");
                        Object returnValue=method.invoke(realSubject,args);
                        System.out.println("宋喆代替王宝强与粉丝互动");return returnValue;
                    }
                }
        );
        proxy.request();
    }
}
  • Cglib代理

public class RealSubject {public void request() {
        System.out.println("王宝强拍电影");
    }
}import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class ProxyFactory implements MethodInterceptor {private Object realSubject;public ProxyFactory(Object realSubject){this.realSubject=realSubject;
    }public Object getProxyInstance(){//1.工具类Enhancer enhancer=new Enhancer();//2.设置父类        enhancer.setSuperclass(realSubject.getClass());//3.设置回调函数enhancer.setCallback(this);//4.创建子类return enhancer.create();
    }public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {
        System.out.println("宋喆代替王宝强维护微博");
        Object returnValue=method.invoke(realSubject,objects);
        System.out.println("宋喆代替王宝强与粉丝互动");return returnValue;
    }
}public class Main {public static void main(String[] args) {
        RealSubject realSubject=new RealSubject();
        RealSubject proxy=(RealSubject)new ProxyFactory(realSubject)
                .getProxyInstance();
        proxy.request();
    }
}
  • 区别:静态代理与JDK动态代理的区别在于一个是写类去组合目标对象,一个去写匿名内部函数,二者相同之处是原类与代理类必须共同实现目标接口。而Cglib则不用实现目标接口。前两者代码维护性相对于Cglib不方便。

  • 应用场景:AOP切面编程通常可以处理事务管理(开启事务、操作、提交事务)、安全检测(权限验证,进入)、缓存(访问数据库、存入缓存)。AOP默认使用动态代理。