结构型 中等

代理模式

Proxy Pattern

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

概述

代理模式是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。

适用场景

  • 延迟初始化(虚拟代理)- 当你有一个偶尔使用的重量级服务对象时
  • 访问控制(保护代理)- 当你需要根据不同客户端的权限控制对服务对象的访问时
  • 本地执行远程服务(远程代理)- 当服务对象位于远程服务器上时
  • 记录日志请求(日志记录代理)- 当你需要保存服务对象的请求历史记录时
  • 缓存请求结果(缓存代理)- 当你需要缓存服务对象的请求结果并管理其生命周期时
  • 智能引用(智能引用代理)- 当需要在对象被访问时执行额外操作(如引用计数)时

优点

  • +可以在客户端毫无察觉的情况下控制服务对象
  • +客户端与真实服务对象解耦,无需知道代理的存在
  • +开闭原则:可以在不对服务或客户端做出修改的情况下创建新代理
  • +单一职责原则:可以将服务实现与代理功能分离
  • +可以在运行时切换代理和真实对象

缺点

  • 代码可能变得复杂,因为需要引入许多新的类
  • 服务响应可能会延迟,因为代理会增加一层间接访问
  • 增加系统复杂度,需要维护代理和真实对象的一致性

结构

classDiagram class Subject { <<interface>> +request() } class RealSubject { +request() } class Proxy { -realSubject: RealSubject -accessControl() -logging() -caching() +request() } class Client { +main() } Subject <|.. RealSubject : implements Subject <|.. Proxy : implements Proxy o--> RealSubject : contains Client ..> Subject : uses style Subject fill:#e3f2fd,stroke:#1976d2,stroke-width:2px style RealSubject fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style Proxy fill:#fff3e0,stroke:#f57c00,stroke-width:2px style Client fill:#f5f5f5,stroke:#616161,stroke-width:1px

交互演示

代理控制对真实对象的访问
Client
Proxy
checklog
RealSubject
💤
lazy

点击"通过代理访问"观察代理如何控制对真实对象的访问

生活类比

代理模式就像是现实生活中的各种代理服务,它们控制着对真实资源的访问,并在访问前后添加额外的功能。

信用卡

信用卡是银行账户的代理,它控制着对账户的访问,并可以在支付前后添加额外的功能(如积分、验证、信用检查)。你不需要随身携带大量现金(真实对象),只需使用信用卡(代理)即可完成支付。

安检门

机场安检门是登机口的代理。它控制着对登机口(真实对象)的访问,在允许通过前执行安全检查(额外功能)。

网页缓存

浏览器缓存是远程服务器的代理。当访问网页时,浏览器先检查本地缓存(代理),如果存在且未过期就直接使用,避免重复请求远程服务器(真实对象)。

代码实现

Example.java

实际应用

Java RMI(远程方法调用)

Java RMI 使用代理模式来访问远程对象。客户端使用 Stub(代理)与远程对象通信,Stub 负责网络通信的细节,对客户端透明。

Example.java

Spring AOP

Spring 框架的面向切面编程(AOP)使用代理模式实现。JDK 动态代理用于接口代理,CGLIB 用于类代理,在方法调用前后添加横切关注点(如事务、日志)。

Example.java

Hibernate 延迟加载

Hibernate 使用代理模式实现关联对象的延迟加载。当访问实体对象的关联集合时,返回的是代理对象,只有在真正访问数据时才从数据库加载。

Example.java

Android 的 Binder 机制

Android 的跨进程通信(IPC)使用 Binder 机制,其中 BinderProxy 是本地进程中的代理,负责将方法调用序列化后传递给远程的 Binder 对象。

Example.java

练习

1

代理模式的主要目的是什么?

2

以下哪些是代理模式的常见类型?

3

代理模式和装饰器模式的主要区别是什么?

4

在 Java 中,JDK 动态代理只能代理实现了接口的类

5

以下哪种情况最适合使用虚拟代理?