设计模式(17):JAVA(17):设计模式(10)代理模式 为其他对象提供一种代理以控制对这个对象的访问

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

一个简单的加减乘除功能

class Test{
    interface Calculator{
        int add(int a,int b);
        int sub(int a,int b);
        int mul(int a,int b);
        int div(int a,int b);
    }
    static class  CalImpl implements Calculator{
        @Override
        public int add(int a, int b) {
            return a+b;
        }

        @Override
        public int sub(int a, int b) {
            return a-b;
        }

        @Override
        public int mul(int a, int b) {
            return a*b;
        }

        @Override
        public int div(int a, int b) {
            return a/b;
        }
    }

    public static void main(String[] args) {
        CalImpl c = new CalImpl();
        System.out.println(c.add(4,2));
        System.out.println(c.sub(4,2));
        System.out.println(c.mul(4,2));
        System.out.println(c.div(4,2));
    }
}

变化来了,要求为每个方法调用前后,都需要打印出一个日志信息

class Test{
    interface Calculator{
        int add(int a,int b);
        int sub(int a,int b);
        int mul(int a,int b);
        int div(int a,int b);
    }
    static class  CalImpl implements Calculator{
        @Override
        public int add(int a, int b) {
            System.out.println("add方法开始!" +"a="+a+"b="+b);
            int r = a+b;
            System.out.println("add方法结束!" +"r="+r);
            return r;
        }

        @Override
        public int sub(int a, int b) {
            System.out.println("sub方法开始!" +"a="+a+"b="+b);
            int r = a-b;
            System.out.println("sub方法结束!" +"r="+r);
            return r;
        }

        @Override
        public int mul(int a, int b) {
            System.out.println("mul方法开始!" +"a="+a+"b="+b);
            int r = a*b;
            System.out.println("mul方法结束!" +"r="+r);
            return r;
        }

        @Override
        public int div(int a, int b) {
            System.out.println("div方法开始!" +"a="+a+"b="+b);
            int r = a/b;
            System.out.println("div方法结束!" +"r="+r);
            return r;
        }
    }

    public static void main(String[] args) {
        CalImpl c = new CalImpl();
        System.out.println(c.add(4,2));
        System.out.println(c.sub(4,2));
        System.out.println(c.mul(4,2));
        System.out.println(c.div(4,2));
    }
}

我们发现,这样完成业务根本不是一个好办法,代码在重复,业务(加减)和非核心业务(打印日志)在不断的重复,需求如果变化要加入开方,求余的过程,或者,需要上午需要日志,下午不需要日志的需求,那我们就需要不断地改写这段代码

我们应该使用动态代理来完成

动态代理:在内存中写入的字节码,直接被类加载器使用

设计模式(17):JAVA(17):设计模式(10)代理模式 为其他对象提供一种代理以控制对这个对象的访问

 

 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

interface Calculator {
    int add(int a, int b);

    int sub(int a, int b);

    int mul(int a, int b);

    int div(int a, int b);
}
class CalImpl implements Calculator {
    @Override
    public int add(int a, int b) {
        int r = a + b;
        return r;
    }

    @Override
    public int sub(int a, int b) {
        int r = a - b;
        return r;
    }

    @Override
    public int mul(int a, int b) {
        int r = a * b;
        return r;
    }

    @Override
    public int div(int a, int b) {
        int r = a / b;
        return r;
    }
}
class MyHandler implements InvocationHandler {
    private Calculator calculator;
    public MyHandler(Calculator calculator) {
        this.calculator = calculator;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName()+"开始,参数:"+ Arrays.toString(args));
        System.out.println(method.getName()+"结束,结果是:"+method.invoke(calculator,args));
        return 0;
    }
}
public class AppTest {
    public static void main(String[] args) {
        Calculator calculator = new CalImpl();
        ClassLoader classLoader = AppTest.class.getClassLoader();
        //创建代理对象
        Calculator cal = (Calculator) Proxy.newProxyInstance(classLoader, new Class[]{Calculator.class}, new MyHandler(calculator));
        cal.add(3, 2);
        cal.sub(3, 2);
        cal.mul(3, 2);
        cal.div(3, 2);
    }
}

动态代理api

Proxy.newProxyInstance(classLoader, new Class[]{Calculator.class}, new MyHandler(calculator)

第一个参数:实例化一个对象,必然会调用类的构造器,运行第一次调用构造器,必定导致类的加载,而加载类的时候,就是jvm拿着classloader去加载类的字节码的,把字节码加载到内存中,才能进一步实例化对象

简单来说:只要实例化的对象,一定要加载类的字节码,加载字节码就一定要类的加载器。

使用动态代理的api实例化对象是一种不常用的方式,但这也是一种实例化,需要我们手动把类的加载器传入

第二个参数:第三个参数:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

第一个参数:第二个参数:第三个参数:调用的接口方法的参数

}

动态代理具体步骤

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  1. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  2. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

 

设计模式(17):JAVA(17):设计模式(10)代理模式 为其他对象提供一种代理以控制对这个对象的访问

上一篇:聊聊spring事务失效的12种场景,太坑了


下一篇:面试二十八、spring循环依赖