设计模式 2

113 阅读2分钟

JAVA设计模式-代理模式

前言

回顾设计模式,让代码变得更加优雅

一、简介

代理模式(Proxy Pattern) 代理类代替目标对象执行功能,并且可以扩展目标对象的功能,又分为静态代理和动态代理

二、举例

设置一个薪酬计算器(目标对象,基本工资计算行为),分为员工薪酬计算器和高管薪酬计算器(代理对象),代理对象不仅能计算基本工资还扩展了其他薪酬体系计算行为

三、静态代理代码实现

/**
 * @Author: 勇少
 * @Date: 30/06/22 15:16
 * @Description: 目标对象,提供计算基本工资行为
 **/
public interface SalaryCalculator {

    double calculate(int id);
}
public class SalaryCalculatorImpl implements SalaryCalculator{

    @Override
    public double calculate(int id) {
        return 1000;
    }
}
/**
 * @Author: 勇少
 * @Date: 30/06/22 15:19
 * @Description: 代理对象
 **/
public class OperationSalaryCalculator implements SalaryCalculator{

    @Override
    public double calculate(int id) {
        System.out.println("补贴功能");
        return 30000;
    }
}
/**
 * @Author: 勇少
 * @Date: 30/06/22 15:19
 * @Description: 代理对象暴露给外部调用
 **/
public class Main {

    public static void main(String[] args) {
        SalaryCalculator operationSalary = new OperationSalaryCalculator();  //运营人员薪酬计算
        double res = operationSalary.calculate(10);
        System.out.println(res);

    }
}

输出:

补贴功能
30000.0

优点

不同的代理类可以复用目标对象的方法,外部无法直接调用目标对象,代理对象无需考虑目标对象的具体实现

缺点

如果目标对象增加了其他的方法,那么所有的代理类也要相应的增加,代码维护复杂

四、JDK动态代理代码实现

/**
 * @Author: 勇少
 * @Date: 17/06/22 15:52
 * @Description: 目标对象
 **/
public interface SalaryCalculator {

    double calculateSalary(int id);
}
/**
 * @Author: 勇少
 * @Date: 30/06/22 16:09
 * @Description: 目标对象的业务实现
 **/
public class SalaryCalculatorImpl implements SalaryCalculator {

    @Override
    public double calculateSalary(int id) {
        return 10000;
    }
}
/**
 * @Author: 勇少
 * @Date: 17/06/22 15:53
 * @Description:
 **/
public class SalaryLogProxy implements InvocationHandler {

    private SalaryCalculator salaryCalculator;

    public SalaryLogProxy(SalaryCalculator salaryCalculator) {
        this.salaryCalculator = salaryCalculator;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("打印日志");

        System.out.println("其他非目标对象拥有的功能");

        return method.invoke(salaryCalculator, args);
    }
}
/**
 * @Author: 勇少
 * @Date: 17/06/22 15:55
 * @Description: 
 **/
public class Main {

    public static void main(String[] args) {

        SalaryCalculator salaryCalculator = new SalaryCalculatorImpl();

        InvocationHandler handler = new SalaryLogProxy(salaryCalculator);
        SalaryCalculator calculator = (SalaryCalculator)Proxy.newProxyInstance(SalaryCalculator.class.getClassLoader(), salaryCalculator.getClass().getInterfaces(), handler);

        double v = calculator.calculateSalary(1);
        System.out.println(v);
    }
}

优点

  • 不需要像静态代理那样在程序运行前新建对应的代理类
  • 动态代理是在代码运行的时候创建的代理类,由JVN动态生成,可以代理多个目标对象
  • 主要有Proxy负责生成动态代理类,其中它的newProxyInstance方法用来生成动态代理类实例
  • InvocationHandler 接口只有invoke()一个方法,利用反射来调用被代理类的制定方法并返回结果。

缺点

  • 基于反射,性能可能比较差
  • 只能接口实现,不支持继承