在某些情况下,一个对象不适合或者不方便直接访问另外一个对象,此时两者间可以通过代理对象来进行数据通讯。
为其他对象提供一种代理以控制对这个对象的访问。
这里我将代理模式分为两种:静态代理和动态代理。
而动态代理又分为两种:JDK代理和Cglib代理。
下面开始对这些代理模式进行详细讲解。
静态代理类在程序运行之前已经存在(通过了编译产生了.class文件),故叫做静态代理。
分析设计模式,最直接最有效的方式是通过类图来分析。
静态代理的类图
由图可以看出,代理对象和目标对象(被代理对象)都实现了IStudent接口,Client对象通过代理对象间接地访问目标对象。
IStudent类
public interface IStudent {
public void study(String name);
}
Student类
public class Student implements IStudent{
@Override
public void study(String name){
System.out.println("我是学生: "+name+" ,开始学习......");
}
}
StudentProxy类
public class StudentProxy implements IStudent{
private IStudent target;//用接口来接收
//传入被代理的对象(传入代理中介的客户)
public StudentProxy(IStudent target){
this.target = target;
}
//代理对象的study函数中,调用了目标对象的study函数,并做了一些准备工作和后序工作
@Override
public void study(String name) {
//准备工作
System.out.println("学习前:做预习......");
target.study(name);
//后序工作
System.out.println("学习后:做习题,做复习......");
}
}
public class Client {
public static void main(String[] args) {
Student student = new Student();
StudentProxy studentProxy = new StudentProxy(student);
studentProxy.study("zs");
}
}
效果:Client类中使用了StudentProxy对象的study函数,但是运行结果是Student对象的study函数的内容。这就好比,一个学霸代替了差生学习,而且还做了预习和复习等工作。
动态代理的代理类是程序运行时动态创建的,避免了硬编码,而且代理类不必与被代理类实现同一个接口,实现了两种的解耦。
之所以叫接口代理,是因为这个模式的代理类运用了InvocationHandler接口。这个接口是一个函数式接口。
Student类
和上述一样
ProxyFactory类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
//为target生成一个代理对象
public Object getProxyFactory(){
/*
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
参数:
1.类加载器
2.目标对象实现接口的类型
3.事件处理,执行target的函数时,会触发该事件
*/
//这里用lambda表达式
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理开始:开始预习");
Object returnVal = method.invoke(target, args);
System.out.println("代理结束:开始复习");
return returnVal;
}
}
);
}
}
该类使用了JDK中的Proxy类和InvocationHandler接口,具体细节比较复杂,偏底层。
我们只需要知道,当客户端程序运行 且 当代理对象维护的函数被调用时,就会执行invoke函数。
Client类
public class Client {
public static void main(String[] args) {
//目标对象
IStudent student = new Student();
//为student 生成代理对象 proxyFactory
IStudent proxyFactory = (IStudent) new ProxyFactory(student).getProxyFactory();
//调用代理对象的study
proxyFactory.study("zs");
}
}
Cglib代理的类图
从类图可以看出,被代理类无需实现任何接口,所有的事情都交给代理方去做。分工更为明确。
Student类
public class Student {
public void study(String name){
System.out.println("Student: "+name+" 开始学习......");
}
}
ProxyFactory类
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target){
this.target = target;
}
public Object getInstance(){
//1.创建一个工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(target.getClass());
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类对象,即代理对象,返回
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理开始:开始预习");
Object returnVal = method.invoke(target, args);
System.out.println("cglib代理结束:开始复习");
return returnVal;
}
}
Client类
public class Client {
public static void main(String[] args) {
Student student = new Student();
Student proxy = (Student)new ProxyFactory(student).getInstance();
proxy.study("zs");
}
}
代理模式是非常常用的,我们熟悉的AOP编程,经常要用到代理模式。
代理模式是的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息,而代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。