代理模式
引言
在软件系统中,当直接访问对象可能导致安全风险(如权限控制)、性能损耗(如大文件加载)或功能限制(如远程调用)时,代理模式应运而生。它通过创建代理对象作为原对象的替身,实现对目标对象的访问控制,成为系统设计中不可或缺的"守门人"。
诞生背景
GoF在《设计模式》中提出代理模式,解决三大核心问题:
- 访问控制:限制敏感资源的直接访问(如数据库连接)
- 性能优化:延迟高成本对象的创建(如图片懒加载)
- 远程交互:为分布式对象提供本地代理(如RPC调用)
演进过程
- 静态代理(1994):手动创建代理类,实现硬编码控制
- 动态代理革命:Java反射/CGLib实现运行时动态代理
- 现代应用:Spring AOP面向切面编程的核心实现机制
- 云原生演进:服务网格(如Istio)中的透明代理架构
核心概念
- 抽象主题(Subject):定义真实对象和代理对象的共用接口
- 真实主题(Real Subject):实际执行业务逻辑的核心对象
- 代理(Proxy):控制对真实主题的访问,可添加额外功能
通用实现
Java 实现(静态代理)
java
// 抽象主题
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("Loading image: " + filename);
}
public void display() {
System.out.println("Displaying: " + filename);
}
}
// 代理类
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
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("high_res.jpg");
// 图片尚未加载
image.display(); // 首次访问时加载并显示
}
}PHP 实现(动态代理)
php
// 抽象主题
interface PaymentService {
public function pay(int $amount): void;
}
// 真实主题
class RealPayment implements PaymentService {
public function pay(int $amount): void {
echo "Processing payment: $amount USD\n";
}
}
// 代理处理器
class PaymentProxy implements \InvocationHandler {
private $target;
public function __construct(PaymentService $target) {
$this->target = $target;
}
public function __call($method, $args) {
if ($method === 'pay') {
$this->preProcess($args[0]);
call_user_func_array([$this->target, $method], $args);
$this->postProcess();
}
}
private function preProcess(int $amount): void {
echo "[Security] Verifying transaction...\n";
}
private function postProcess(): void {
echo "[Log] Payment recorded in audit trail\n";
}
}
// 客户端
$realPayment = new RealPayment();
$proxy = new PaymentProxy($realPayment);
$proxy->pay(100); // 通过代理执行应用场景
- 虚拟代理:延迟大资源加载(如图片/视频)
- 保护代理:控制敏感资源访问权限
- 远程代理:为远程对象提供本地代表(如RPC)
- 智能引用:添加额外操作(引用计数/日志记录)
- 缓存代理:为高成本运算提供结果缓存
案例:文档访问控制系统
Java 实现(保护代理)
java
// 抽象主题
interface Document {
void view();
}
// 真实主题
class SensitiveDocument implements Document {
public void view() {
System.out.println("Displaying classified content");
}
}
// 保护代理
class DocumentProxy implements Document {
private SensitiveDocument doc;
private String userRole;
public DocumentProxy(String userRole) {
this.userRole = userRole;
}
public void view() {
if (checkAccess()) {
if (doc == null) {
doc = new SensitiveDocument();
}
doc.view();
} else {
System.out.println("Access denied: Insufficient privileges");
}
}
private boolean checkAccess() {
return "admin".equals(userRole);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Document userDoc = new DocumentProxy("guest");
userDoc.view(); // Access denied
Document adminDoc = new DocumentProxy("admin");
adminDoc.view(); // Displaying classified content
}
}PHP 实现(缓存代理)
php
// 抽象主题
interface DataFetcher {
public function fetchData(string $key): string;
}
// 真实主题
class DatabaseFetcher implements DataFetcher {
public function fetchData(string $key): string {
echo "Executing expensive database query...\n";
// 模拟耗时操作
sleep(2);
return "Data for: $key";
}
}
// 缓存代理
class CachingProxy implements DataFetcher {
private $fetcher;
private $cache = [];
public function __construct(DataFetcher $fetcher) {
$this->fetcher = $fetcher;
}
public function fetchData(string $key): string {
if (!isset($this->cache[$key])) {
$this->cache[$key] = $this->fetcher->fetchData($key);
}
return "[Cached] " . $this->cache[$key];
}
}
// 客户端
$realFetcher = new DatabaseFetcher();
$proxy = new CachingProxy($realFetcher);
echo $proxy->fetchData("user_123") . "\n"; // 首次查询数据库
echo $proxy->fetchData("user_123") . "\n"; // 返回缓存结果优点
- 访问控制:精细化权限管理
- 性能优化:延迟加载/缓存提升响应速度
- 开闭原则:新增代理不影响现有代码
- 职责清晰:分离核心逻辑与辅助功能
缺点
- 响应延迟:代理层增加额外调用开销
- 复杂度增加:需维护额外代理类
- 层级嵌套:多层代理可能导致调试困难
扩展
- 动态代理:
- Java:
InvocationHandler+Proxy.newProxyInstance() - PHP:
__call()魔术方法实现动态拦截
- 虚拟代理集群:
- 管理分布式对象的代理池(如数据库连接池)
- 智能代理链:
- 组合多个代理形成处理流水线(缓存→验证→日志)
模式协作
- 与装饰器模式:代理控制访问,装饰器增强功能(两者结构相似但目的不同)
- 与适配器模式:代理使用相同接口,适配器转换不同接口
- 与外观模式:代理控制单个对象,外观封装整个子系统
- 与观察者模式:代理可触发状态变更通知(如缓存失效事件)
延伸思考
- 微服务架构:Service Mesh中Envoy代理实现服务间安全通信
- 前端性能优化:图片懒加载代理(IntersectionObserver API)
- 区块链应用:智能合约作为资产交易的代理中介
- 安全边界:API网关作为微服务的保护代理(鉴权/限流)
总结
代理模式是对象访问控制的精密阀门,通过代理对象对真实对象的访问进行拦截和管控。其核心价值在于:安全防护的守门人、性能优化的调度师和远程交互的本地大使。在现代分布式系统、高性能应用和安全敏感场景中,代理模式展现出不可替代的作用,成为构建健壮软件架构的关键模式。