Skip to content

代理模式(Proxy Pattern)

1. 官方定义

"Provide a surrogate or placeholder for another object to control access to it."
—— 《Design Patterns: Elements of Reusable Object-Oriented Software》(GoF, 1994)

核心:为其他对象提供一种代理以控制对这个对象的访问。


2. 模式解释

核心思想

  • 访问控制:代理对象作为中间层,控制对真实对象的访问(如权限校验、延迟加载)。
  • 透明性:客户端无感知代理与真实对象的差异,两者实现相同接口。
  • 职责分离:代理类处理非核心逻辑(如日志、缓存),真实对象专注业务功能。

典型结构

plaintext
          Client → |<<Interface>>|
                     Subject

                        | implements
            ┌───────────┴───────────┐
            |                       |
      RealSubject               Proxy

                                      | holds a RealSubject

优点

  • 安全控制:保护真实对象不被直接访问(如防火墙代理)。
  • 性能优化:延迟加载大资源(如图片懒加载)。
  • 功能扩展:无侵入式添加日志、监控等横切关注点。

缺点

  • 复杂度增加:引入额外类可能使系统结构复杂化。
  • 调用链延长:代理转发请求可能导致性能损耗(如远程调用)。

3. 解决的问题

经典场景

  1. 远程代理(Remote Proxy)
    • 访问远程对象(如 RPC 调用,客户端代理处理网络通信)。
  2. 虚拟代理(Virtual Proxy)
    • 延迟加载大资源(如网页图片占位符,滚动到视图时加载真实图片)。
  3. 保护代理(Protection Proxy)
    • 权限校验(如仅管理员可访问敏感数据)。
  4. 智能引用(Smart Reference)
    • 自动清理缓存、统计访问次数等。

4. 实现注意事项

关键实现点

  1. 接口一致性
    • 代理与真实对象必须实现相同接口(否则需适配器模式配合)。
  2. 代理类型选择
    • 静态代理:手动编写代理类,适合简单场景。
    • 动态代理:运行时生成代理类(如 JDK 动态代理、CGLIB)。
  3. 性能权衡
    • 动态代理生成字节码有启动开销,但减少编码量。

代码示例(JDK 动态代理)

java
// 接口
interface Database {
    void query(String sql);
}

// 真实对象
class RealDatabase implements Database {
    public void query(String sql) { /* 执行查询 */ }
}

// 代理处理器
class LoggingHandler implements InvocationHandler {
    private Database realDatabase;

    public LoggingHandler(Database database) {
        this.realDatabase = database;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Log: Query executed - " + args[0]);
        return method.invoke(realDatabase, args);
    }
}

// 客户端调用
Database proxy = (Database) Proxy.newProxyInstance(
    Database.class.getClassLoader(),
    new Class[]{Database.class},
    new LoggingHandler(new RealDatabase())
);
proxy.query("SELECT * FROM users");

5. 实现变体

类型特点适用场景
静态代理手动编写代理类,直接持有真实对象引用代理逻辑简单,接口稳定
JDK 动态代理基于接口生成代理类(需实现 InvocationHandler需要动态代理多个接口
CGLIB 动态代理通过继承生成子类代理(可代理无接口的类)代理无接口的类
远程代理处理网络通信和序列化(如 Java RMI)分布式系统调用

6. 相似模式对比

模式核心区别
装饰器模式增强对象功能,代理模式控制对象访问
适配器模式解决接口不兼容问题,代理模式保持接口一致
外观模式简化复杂子系统访问,代理模式控制单个对象访问

7. 组合使用场景

常见搭配模式

  1. 工厂模式
    • 场景:由工厂决定返回真实对象或代理(如根据配置启用缓存代理)。
  2. 单例模式
    • 场景:代理类本身需全局唯一(如数据库连接池代理)。
  3. 观察者模式
    • 场景:代理触发事件通知(如资源加载完成时通知监听器)。

总结
代理模式是系统访问控制的守门人,核心价值在于间接访问逻辑解耦。其动态代理实现(如 Spring AOP)是 Java 生态的基石技术。需注意代理滥用导致的性能问题和过度设计风险,合理选择代理类型以平衡灵活性与复杂度。```