代理模式(Proxy Pattern)学习笔记

1. 模式定义

结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。通过引入代理对象,在客户端和目标对象之间起到中介作用。

2. 适用场景

✅ 远程代理(Remote Proxy):为不同地址空间的对象提供代理
✅ 虚拟代理(Virtual Proxy):延迟创建开销大的对象
✅ 保护代理(Protection Proxy):控制不同权限的访问
✅ 智能引用代理(Smart Reference):添加额外操作(如引用计数)
✅ AOP实现、日志记录、事务管理等横切关注点

3. 模式结构

«interface»
Subject
+request()
RealSubject
+request()
Proxy
-realSubject: RealSubject
+request()
+preRequest()
+postRequest()
Client
+doOperation()

4. 核心角色

角色 说明
Subject 抽象主题接口,声明真实主题和代理的共同接口
RealSubject 真实主题类,定义代理所代表的真实对象
Proxy 代理类,持有真实主题的引用,提供与真实主题相同的接口
Client 客户端,通过代理对象间接访问真实主题

5. 实现方式对比

类型 实现方式 优点 缺点
静态代理 手动创建代理类 简单直观 类膨胀,接口修改需要同步维护
JDK动态代理 基于接口,使用ProxyInvocationHandler 无需实现大量代理类 只能代理接口
CGLIB代理 基于字节码生成子类 可以代理普通类 无法代理final类和方法

6. 代码示例

6.1 静态代理示例

// 抽象主题
interface Image {
    void display();
}

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

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

    private void loadFromDisk() {
        System.out.println("加载图片: " + filename);
    }

    @Override
    public void display() {
        System.out.println("显示图片: " + filename);
    }
}

// 代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;

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

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

// 客户端
public class Client {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        image.display(); // 真实对象被创建
        image.display(); // 直接使用已创建对象
    }
}

6.2 JDK动态代理示例

import java.lang.reflect.*;

// 抽象主题
interface UserService {
    void addUser(String name);
}

// 真实主题
class UserServiceImpl implements UserService {
    public void addUser(String name) {
        System.out.println("添加用户: " + name);
    }
}

// 代理处理器
class LogHandler implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("[日志] 方法调用: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("[日志] 方法完成: " + method.getName());
        return result;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        UserService realService = new UserServiceImpl();
        UserService proxy = (UserService) Proxy.newProxyInstance(
            realService.getClass().getClassLoader(),
            realService.getClass().getInterfaces(),
            new LogHandler(realService)
        );
        proxy.addUser("张三");
    }
}

7. 模式变种

  1. 远程代理:处理网络通信细节(如RPC调用)
  2. 虚拟代理:延迟加载大资源对象
  3. 防火墙代理:控制网络资源的访问
  4. 同步代理:提供多线程安全访问
  5. 缓存代理:为开销大的运算结果提供缓存

8. 优缺点分析

✔️ 优点

  • 职责清晰,高扩展性
  • 保护真实对象,控制访问细节
  • 降低系统耦合度
  • 支持横切关注点集中处理

缺点

  • 增加系统复杂度
  • 动态代理使用反射影响性能
  • 代理模式可能造成请求处理变慢

9. 相关模式对比

模式 目的 关键区别
装饰者模式 增强功能 关注对象功能的增强
适配器模式 接口转换 主要解决接口不兼容问题
外观模式 简化接口 组合多个子系统接口

10. 实际应用案例

  • Spring AOP的动态代理实现
  • MyBatis的Mapper接口代理
  • Java RMI远程方法调用
  • Hibernate的延迟加载(Lazy Loading)
  • Servlet的FilterChain
  • Retrofit的网络请求接口

11. 最佳实践建议

  1. 优先使用JDK动态代理(标准库支持)
  2. 需要代理普通类时使用CGLIB
  3. 注意代理方法的性能影响
  4. 避免过度使用导致系统复杂性增加
  5. 使用代理模式实现横切关注点时,结合AOP框架
  6. 对关键业务方法添加访问日志时使用保护代理

🔑 记忆技巧:把代理模式想象成明星的经纪人,客户端(粉丝)通过经纪人(代理)与明星(真实对象)进行互动。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐