欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

代理-->静态代理&动态代理

程序员文章站 2022-06-10 20:49:27
...

Proxy(代理)模式是一种常用的设计模式,主要为了解决直接访问对象时带来的问题。

代理模式是一种常见的模式,为某一对象提供一个代理对象以控制对此对象的访问。代理对象负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

静态代理

由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
创建接口:

public interface Calculate {
    public void add();
    public void sub();
    public void mul();
    public void dev();
}

真实对象实现此接口:

//计算器
public class Calculator implements Calculate {

    @Override
    public void add() {
        System.out.println("Calculator.add()");
    }

    @Override
    public void dev() {
        System.out.println("Calculator.dev()");
    }

    @Override
    public void mul() {
        System.out.println("Calculator.mul()");
    }

    @Override
    public void sub() {
        System.out.println("Calculator.sub()");
    }

}

代理对象实现此接口:

public class CalculateProxy implements Calculate {

    private Calculate calculator;

    public CalculateProxy(Calculate calculator){
        this.calculator = calculator;
    }

    @Override
    public void add() {
        System.out.println("开始记录加法日志");
        calculator.add();
    }

    @Override
    public void dev() {
        System.out.println("开始记录除法日志");
        calculator.dev();
    }

    @Override
    public void mul() {
        System.out.println("开始记录乘法日志");
        calculator.mul();
    }

    @Override
    public void sub() {
        System.out.println("开始记录减法日志");
        calculator.sub();
    }

}

客户端调用:

public static void main(String[] args) {
        Calculate calculator = new CalculateProxy(new Calculator());
        calculator.add();
}

客户就像使用真实对象一样使用代理对象,而不需要关心真实对象。
静态代理的优缺点:
优点:客户不需要知道真实对象具体是什么,只需要了解代理对象即可。
缺点:一旦在公共接口中添加一个方法,我们不仅需要修改真实对象,也需要修改代理对象,这很繁琐。一个代理类只为特定的接口服务,如果要为多个接口提供服务我们需要实现对个代理类。


动态代理

动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类
真实角色同上。
代理类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class CalculateHandler implements InvocationHandler{

    private Calculate calculate;

    public CalculateHandler(Calculate calculate){
        this.calculate = calculate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("开始记录日志!");
        Object object = method.invoke(calculate, args);
        return object;
    }

}

客户端:

public static void main(String[] args) {
        Calculate calculator = new Calculator();
        CalculateHandler  handler = new CalculateHandler(calculator);
        Calculate proxy = (Calculate) Proxy.newProxyInstance(calculator.getClass().getClassLoader(), calculator.getClass().getInterfaces(), handler);//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
        proxy.add();
}

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强