设计模式详细解析(2) 代理模式

代理模式

引言

在某些情况下,一个对象不适合或者不方便直接访问另外一个对象,此时两者间可以通过代理对象来进行数据通讯。

定义

为其他对象提供一种代理以控制对这个对象的访问。

代理模式通用类图
设计模式详细解析(2) 代理模式_第1张图片

两种代理模式

这里我将代理模式分为两种:静态代理和动态代理。
而动态代理又分为两种:JDK代理和Cglib代理。
下面开始对这些代理模式进行详细讲解。

静态代理

静态代理类在程序运行之前已经存在(通过了编译产生了.class文件),故叫做静态代理。
分析设计模式,最直接最有效的方式是通过类图来分析。

静态代理的类图
设计模式详细解析(2) 代理模式_第2张图片
由图可以看出,代理对象和目标对象(被代理对象)都实现了IStudent接口,Client对象通过代理对象间接地访问目标对象。

类目录
设计模式详细解析(2) 代理模式_第3张图片

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");
    }
}

运行结果
设计模式详细解析(2) 代理模式_第4张图片

效果:Client类中使用了StudentProxy对象的study函数,但是运行结果是Student对象的study函数的内容。这就好比,一个学霸代替了差生学习,而且还做了预习和复习等工作。

动态代理

动态代理的代理类是程序运行时动态创建的,避免了硬编码,而且代理类不必与被代理类实现同一个接口,实现了两种的解耦。

接口代理

之所以叫接口代理,是因为这个模式的代理类运用了InvocationHandler接口。这个接口是一个函数式接口。

接口代理的类图
设计模式详细解析(2) 代理模式_第5张图片

类目录
设计模式详细解析(2) 代理模式_第6张图片
IStudent接口
和上述一样

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");
    }
}

运行结果
设计模式详细解析(2) 代理模式_第7张图片

Cglib代理

Cglib代理的类图
设计模式详细解析(2) 代理模式_第8张图片
从类图可以看出,被代理类无需实现任何接口,所有的事情都交给代理方去做。分工更为明确。

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编程,经常要用到代理模式。
代理模式是的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息,而代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

你可能感兴趣的:(设计模式,JAVA)