设计模式-代理模式(静态代理 动态代理)

代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以附加额外的功能,如访问控制、日志记录、延迟初始化等,而不需要修改目标对象的代码。

代理模式分为静态代理和动态代理两种实现方式。

1. 静态代理

静态代理是在编译期间就确定下来的代理类,它直接实现了目标接口,对目标方法进行了包装和增强。

假设我们有一个Image接口和它的实现类RealImage,我们通过静态代理ImageProxy来实现图片加载的延迟加载。

// 目标接口
interface Image {
    void display();
}

// 真实主题类
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(filename);
    }

    private void loadFromDisk(String filename) {
        System.out.println("Loading image from disk: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

// 静态代理类
class ImageProxy implements Image {
    private RealImage realImage;
    private String filename;

    public ImageProxy(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

客户端代码:

public class StaticProxyDemo {
    public static void main(String[] args) {
        Image image = new ImageProxy("image.jpg");
        image.display();
    }
}

2. 动态代理

动态代理则是在运行时通过反射机制动态生成的代理类,它不需要预先定义代理类,更加灵活。

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

// 目标接口同上

// 动态代理处理器
class DynamicProxyHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method call: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method call: " + method.getName());
        return result;
    }
}

客户端代码:

public class DynamicProxyDemo {
    public static void main(String[] args) {
        RealImage realImage = new RealImage("image.jpg");
        Image proxyInstance = (Image) Proxy.newProxyInstance(
                RealImage.class.getClassLoader(),
                new Class[]{Image.class},
                new DynamicProxyHandler(realImage)
        );
        proxyInstance.display();
    }
}

3. 优点:

  1. 代理模式提供了一种对目标对象的访问控制手段,可以在不修改目标对象的基础上,增加额外的功能,如权限校验、日志记录等。
  2. 动态代理提高了系统的灵活性和可扩展性,可以在运行时根据需要动态创建代理对象,无需修改代码。
  3. 静态代理实现简单直观,适用于那些代理逻辑相对固定的情况。

4. 缺点:

  1. 静态代理需要为每一个目标类创建代理类,当目标类数量众多时,会导致类的数量激增,增加了系统的复杂度。
  2. 动态代理依赖于反射,可能会有性能开销,尤其是在大量使用时需要注意。
  3. 代理模式增加了系统的复杂度,尤其是对于新手来说,理解代理模式的工作原理和使用场景可能会有一定难度。