你管这叫代理模式(Proxy Pattern)

代理模式

  代理模式即给一个真实类提供一个代理类,该代理类代替真实类完成其功能,一般还可在代理类上添加一些真实类不具有的附加功能,通俗来讲代理模式就是我们生活中常见的中介,代理模式又可分为静态代理动态代理

静态代理

  静态代理需要代理类和目标类实现一样的接口,一般将被代理对象组合到代理类中,然后使用其完成对应功能,并可在代理类中添加额外功能。

租房静态代理过程

第一步:创建服务接口

public interface Rent {
    // 出租房屋
    void rent();
}

第二步:实现类实现服务接口

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子...");
    }
}

第三步:代理类实现服务接口

public class Proxy implements Rent{
	// 被代理的类,用于完成被代理类功能。
    private Host host;
	// 用于初始化被代理类
    public void setHost(Host host) {
        this.host = host;
    }
	// 完成被代理类的功能,同时可附加其他功能。
    @Override
    public void rent() {
        doSomething();
        host.rent();
        doSomething();
    }
    // 附加的功能
    private void doSomething() {
        System.out.println("doSomething...");
    }
}

第四步:编写测试类

public class Test {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy();
        proxy.setHost(host);
        proxy.rent();
    }
}

静态代理总结

优点

  • 高扩展性:可以在不修改目标类的前提下扩展目标类的功能。

缺点

  • 冗余:一个目标类就会产生一个代理类,会产生过多的代理类。
  • 开发效率低:代理类代码量繁重。
  • 不易维护:一旦接口改变,目标类与代理类都要进行修改。

动态代理

  动态代理中我们不需要手动的创建代理类,只需要编写一个动态处理器来为我们动态创建代理对象,代理对象由 JDK 在运行时动态创建,动态代理基于反射来实现

常用的动态代理方式

  • 基于接口的动态代理:由 JDK 提供,使用 JDK 官方的 Proxy 类创建代理对象。
  • 基于类的动态代理:由第三方 CGLib 提供,使用 CGLib 的 Enhancer 类创建代理对象
  • javassist
  • ……

基于接口的动态代理

  使用基于接口的动态代理首先需要了解 JDK 中的 Proxy 类和 InvocationHandler接口,然后用其编写动态处理器用于完成动态代理。

Proxy 类

  Proxy 提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
  一般使用 Proxy 的 newProxyInstance 静态方法创建代理类,需要提供一个类加载器、被代理类的服务接口,以及一个 InvocationHandler 的对象。

  • 类加载器:用于加载类和接口
  • 被代理类的接口:提供被代理类服务接口信息
  • InvocationHandler 对象:用于执行被代理类的方法
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h);

InvocationHandler 接口

  当在代理实例上调用方法时,方法调用被编码并分派到其调用处理程序的调用方法,即在 Proxy 中调用方法时,该方法调用被分派给 InvocationHandler 对象中的 invoke 方法执行,由 invoke 方法调用执行被代理对象的方法。

Object invoke(Object proxy, Method method, Object[] args);

动态处理器工具类

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

public class ProxyInvocationHandler implements InvocationHandler {
    // 被代理的接口
    private Object target;
    
    public ProxyInvocationHandler() {
    }

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

    // 用于初始化被代理类
    public void setTarget(Object target) {
        this.target = target;
    }

    // 生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    // 处理代理示例并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }
}

基于接口的租房动态代理过程

第一步:创建服务接口

public interface Rent {
    // 出租房屋
    void rent();
}

第二步:实现类实现服务接口

public class Host implements Rent{
    @Override
    public void rent() {
        System.out.println("房东要出租房子...");
    }
}

第三步:编写动态处理器

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

public class ProxyInvocationHandler implements InvocationHandler {
    // 被代理的接口
    private Object target;

    // 用于初始化被代理类
    public void setTarget(Object target) {
        this.target = target;
    }

    // 生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    // 处理代理示例并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doSomething();
        Object invoke = method.invoke(target, args);
        doSomething();
        return invoke;
    }

    // 附加的功能
    private void doSomething() {
        System.out.println("doSomething...");
    }
}

第四步:编写测试类

public class Test {
    public static void main(String[] args) {
        Host host = new Host();
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
        proxyInvocationHandler.setTarget(host);
        Rent proxy = (Rent)proxyInvocationHandler.getProxy();
        proxy.rent();
    }
}

动态代理总结

优点

  • 高扩展性:可以在不修改目标类的前提下扩展目标类的功能。
  • 低冗余:会产生过多的代理类。
  • 低耦合:减少了对业务接口的依赖。
  • 高效开发:大大减少开发任务,一个动态处理器即可完成代理。

注意事项

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
  • 和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
上一篇:动态代理jdk的Proxy与spring的CGlib


下一篇:arduino环境搭建