设计模式之动态代理

设计模式之动态代理

    • 三要素
    • 反例
    • 示例
    • 优点

何为代理,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理。何为代理模式,为其他对象提供一种代理以控制对这个对象的访问。

三要素

  • Subject抽象主题角色。可以是抽象类,也可以是接口
  • RealSubject。具体主题角色,也就是被代理角色
  • Proxy代理主题角色。也叫做为委托类,代理类。它负责对真实主题的调用,把所有抽象主题类定义的方法委托给真实主题角色的实现,并且在真实主题角色处理完毕后前后做预处理和善后工作。

反例

下面的示例中,以实现一个简单的计算器为例,这个计算可以计算加法和减法,并且将结果进行输出

先定义一个计算器接口:

/**
 * @author:xiapeng
 * @description:计算器接口(Subject抽象主题角色)
 * @date: 2018-10-22 11:06
 * @version: 1.0
 */
public interface Calculator {

    int add(int x, int y);

    int sub(int x, int y);
}

计算器实现类

/**
 * CalculatorImpl
 *
 * @author xiapeng
 * @version 1.0
 * @description 计算器实现类
 * @date 2018-10-22 11:07
 */
public class CalculatorImpl implements Calculator {

    @Override
    public int add(int x, int y) {
        int c = x + y;
        System.out.println("add方法结果为:" + c);
        return c;
    }

    @Override
    public int sub(int x, int y) {
        int c = x - y;
        System.out.println("sub方法结果为:" + c);
        return c;
    }
}

client类:

/**
 * Client
 *
 * @author xiapeng
 * @version 1.0
 * @description 客户端计算
 * @date 2018-10-22 11:12
 */
public class Client {

    public static void main(String[] args) {
        Calculator calculator = new CalculatorImpl();
        calculator.add(10, 6);
        System.out.println("--------------------------------------------------------------------");
        calculator.sub(10, 6);
    }
}

以上做法是不推荐的,如果计算以后新增了一个乘法除法,也需要记录日志,是不是也得在具体实现方法里面加上日志代码呐?接下来介绍使用动态代理来实现该功能

示例

计算器实现类:

/**
 * CalculatorImpl
 *
 * @author xiapeng
 * @version 1.0
 * @description 计算器实现类(RealSubject)
 * @date 2018-10-22 11:07
 */
public class CalculatorImpl implements Calculator {

    @Override
    public int add(int x, int y) {
        int c = x + y;
        return c;
    }

    @Override
    public int sub(int x, int y) {
        int c = x - y;
        return c;
    }
}

日志处理类:

/**
 * LoggingHandler
 *
 * @author xiapeng
 * @version 1.0
 * @description 日志处理(Proxy代理主题角色)
 * @date 2018-10-22 11:10
 */
public class LoggingHandler implements InvocationHandler {
    private Calculator calculator;

    public LoggingHandler(Calculator calculator) {
        this.calculator = calculator;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(calculator, args);
        System.out.println(method.getName() + "方法结果为:" + result);
        return result;
    }
}

客户端:

/**
 * Client
 *
 * @author xiapeng
 * @version 1.0
 * @description 客户端计算
 * @date 2018-10-22 11:12
 */
public class Client {

    public static void main(String[] args) {
        Calculator calculator = new CalculatorImpl();
        Calculator proxiedCalculator = (Calculator) Proxy.newProxyInstance(
            calculator.getClass().getClassLoader(),
            calculator.getClass().getInterfaces(),
            new LoggingHandler(calculator)
        );

        proxiedCalculator.add(10, 6);
        System.out.println("--------------------------------------------------------------------");
        proxiedCalculator.sub(10, 6);
    }
}

相比反例中的代码,这段代码的好处就是如果计算器增加了计算方法,如乘法,除法,记录日志时,不需要耦合到具体实现类,换言之,不需要为加减乘除的每个方法里面增加日志代码,而在Proxy代理主题角色(LoggingHandler.java)进行处理。

优点

  • 职责清晰。真实的角色就只是实现业务逻辑,不用关心其他事务。
  • 高扩展性。RealSubject(具体主题实现)无论如何变化,只要他实现了Subject(抽象主题)的接口,都可以被代理。

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