设计模式之代理模式

概念

它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦

调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

场景模拟

定义一个计算器,用于计算加减乘除

public interface Calculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);    
    int div(int i, int j);    
}
public class CalculatorImpl implements Calculator {    
    @Override
    public int add(int i, int j) {    
        int result = i + j;    
        System.out.println("方法内部 result = " + result);   
        return result;
    }
    
    @Override
    public int sub(int i, int j) {    
        int result = i - j;  
        System.out.println("方法内部 result = " + result); 
        return result;
    }
    
    @Override
    public int mul(int i, int j) {    
        int result = i * j;    
        System.out.println("方法内部 result = " + result);  
        return result;
    }
    
    @Override
    public int div(int i, int j) {   
        int result = i / j;   
        System.out.println("方法内部 result = " + result);   
        return result;
    }
}

思考:如果想在计算之前和之后都加一个日志输出,应该怎么实现?

1. 写在每个方法内部

优点:实现简单

缺点:代码冗余,耦合性太强

2. 使用静态代理

3. 使用动态代理

public class ProxyFactory {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxy(){

        /**
         * newProxyInstance():创建一个代理实例
         * 其中有三个参数:
         * 1、classLoader:加载动态生成的代理类的类加载器
         * 2、interfaces:目标对象实现的所有接口的class对象所组成的数组
         * 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
         */
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * proxy:代理对象
                 * method:代理对象需要实现的方法,即其中需要重写的方法
                 * args:method所对应方法的参数
                 */
                Object result = null;
                try {
                    System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                    result = method.invoke(target, args);
                    System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                } finally {
                    System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                }
                return result;
            }
        };

        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

测试类

@Test
public void testDynamicProxy(){
    ProxyFactory factory = new ProxyFactory(new CalculatorLogImpl());
    Calculator proxy = (Calculator) factory.getProxy();
    proxy.div(1,0);
    //proxy.div(1,1);
}

其他地方用到的动态代理