图形化描述代理模式
-
代理模式概念:
- 结构型模式。它的作用是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。
-
代理模式实例代码
-
-
定义接口
-
public interface Calculator { double add(double a, double b); double sub(double a, double b); double mul(double a, double b); double div(double a, double b); }
-
-
实现接口(核心代码)
-
public class CalculatorImpl implements Calculator { @Override public double add(double a, double b) { return a + b; } @Override public double sub(double a, double b) { return a - b; } @Override public double mul(double a, double b) { return a * b; } @Override public double div(double a, double b) { return a / b; } }
-
-
-
静态代理:
-
借用代理模式调用接口实现额外业务
-
public class CalculatorStaticProxy implements Calculator { private CalculatorImpl target; public CalculatorStaticProxy(CalculatorImpl target) { this.target = target; } @Override public double add(double a, double b) { System.out.println("日志,方法:add,参数:" + a + "、" + b); double res = target.add(a, b); System.out.println("日志,方法:add,结果:" + res); return res; } @Override public double sub(double a, double b) { System.out.println("日志,方法:sub,参数:" + a + "、" + b); double res = target.sub(a, b); System.out.println("日志,方法:sub,结果:" + res); return res; } @Override public double mul(double a, double b) { System.out.println("日志,方法:mul,参数:" + a + "、" + b); double res = target.mul(a, b); System.out.println("日志,方法:mul,结果:" + res); return res; } @Override public double div(double a, double b) { System.out.println("日志,方法:div,参数:" + a + "、" + b); double res = target.div(a, b); System.out.println("日志,方法:div,结果:" + res); return res; } }
-
-
进行静态代理类测试
-
public class staticProxyTest { @Test public void testStaticProxy() { CalculatorStaticProxy proxy = new CalculatorStaticProxy(new CalculatorImpl()); proxy.add(1, 2); } }
-
测试结果
- 日志,方法:add,参数:1.0、2.0
日志,方法:add,结果:3.0
- 日志,方法:add,参数:1.0、2.0
-
-
静态代理类的总结:
虽然实现了解耦,但是由于代码已经写死,不具备任何灵活性。如上代码所示实现的日志功能来说,如果有其他地方也需要用到这个日志功能,那么就需要多个静态代理类来实现,就会产生大量冗余的代码,并且日志功能也没有一个统一的管理。
-
-
JDK 动态代理 (要求必须有接口)
-
最终生成的代理类和目标类实现相同的接口。在com.sun.proxy包下,类名为$proxy2
- 动态代理的工具类实现
public class ActionProxyFactory { private Object target; public ActionProxyFactory(Object target) { this.target = target; } public Object getProxyFactory() { /** * ClassLoader loader, 指定加载动态生成的代理类的类加载器 * Class[] interfaces, 获取目标对象实现的所有的接口的Class对象的数组 * InvocationHandler h 设置代理类中的抽象方法如何重写 */ ClassLoader classLoader = this.getClass().getClassLoader(); Class<?>[] interfaces = target.getClass().getInterfaces(); InvocationHandler h = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // proxy 表示代理对象 method 表示要执行的方法 args 表示 执行的方法的参数列表 System.out.println("日志,方法:" + method.getName() + ",参数:" + Arrays.toString(args)); Object result = method.invoke(target, args); System.out.println("日志,方法:" + method.getName() + ",结果:" + result); return result; } }; return Proxy.newProxyInstance(classLoader, interfaces, h); } }
- 动态代理测试代码
public class actionProxyTest { @Test public void testActionProxy() { ActionProxyFactory proxyFactory = new ActionProxyFactory(new CalculatorImpl()); Calculator proxy = (Calculator) proxyFactory.getProxyFactory(); // -- 我们不知道程序内部实现的类名,但是我们知道这个类实现的接口 proxy.add(1, 2); } }
-
-
动态代理模式的优点:
相比较于静态代理模式,动态代理不仅拥有灵活性,而且实现了代码的复用,也可以对新增功能进行一个统一的管理。