代理模式深度指南:构建控制访问的艺术
Source: Dev.to
代理模式概述
核心角色
| 角色 | 说明 |
|---|---|
| Subject(抽象主题) | 定义了 RealSubject 与 Proxy 的公共接口 |
| RealSubject(真实主题) | 真正执行业务逻辑的对象 |
| Proxy(代理) | 持有 RealSubject 的引用,在需要时创建或访问真实对象 |
| Client(客户端) | 通过 Proxy 与真实对象交互,感知不到真实对象的存在 |
典型的调用链如下:
客户端 → 本地代理 → 网络 → 远程服务
代理模式的典型应用
延迟加载(虚拟代理)
在需要访问代价高昂的资源(如远程图片)时,只有在真正需要时才创建真实对象。
class VirtualProxyImage:
def __init__(self, url):
self.url = url
self._real_image = None
def display(self):
# 首次调用时才加载真实图片
if not self._real_image:
self._real_image = RealImage(self.url)
self._real_image.display()
访问控制
代理可以在调用前进行身份验证或权限检查,类似公司门禁系统。
缓存与懒加载示例
下面的示例展示了如何使用代理实现图片的懒加载与缓存,避免重复的磁盘读取。
from abc import ABC, abstractmethod
import time
# 抽象主题
class Image(ABC):
@abstractmethod
def display(self):
pass
# 真实主题
class RealImage(Image):
def __init__(self, filename):
self.filename = filename
self._load_from_disk()
def _load_from_disk(self):
print(f"正在加载图片: {self.filename}")
time.sleep(1) # 模拟加载时间
print("加载完成!")
def display(self):
print(f"显示图片: {self.filename}")
# 虚拟代理
class ProxyImage(Image):
def __init__(self, filename):
self.filename = filename
self._real_image = None
def display(self):
if self._real_image is None:
self._real_image = RealImage(self.filename)
self._real_image.display()
# 使用示例
print("=== 第一次显示 ===")
img = ProxyImage("photo.jpg")
img.display()
print("\n=== 第二次显示 ===")
img.display()
运行结果
=== 第一次显示 ===
正在加载图片: photo.jpg
加载完成!
显示图片: photo.jpg
=== 第二次显示 ===
显示图片: photo.jpg
代理模式特性对比
| 特性 | 代理模式 | 装饰器模式 |
|---|---|---|
| 目的 | 控制访问、延迟加载、权限校验 | 动态添加功能、增强行为 |
| 关系 | 替代真实对象 | 包装真实对象 |
| 创建时机 | 预先或运行时创建 | 运行时包装 |
| 客户端感知 | 无感知(透明代理) | 感知到额外的装饰层 |
实际案例
连接池(资源代理)
连接池本质上是对数据库/网络连接的代理:预先创建一定数量的连接,客户端从代理获取连接,用完后归还,而不是每次都新建。
API 限流代理
在高并发系统中,代理可以实现请求速率限制,保护后端服务不被过载。
import time
class RateLimitedProxy:
def __init__(self, real_service, max_requests, time_window):
self.real_service = real_service
self.max_requests = max_requests
self.time_window = time_window
self.requests = [] # 记录请求时间戳
def call(self, *args, **kwargs):
now = time.time()
# 清理已过期的请求记录
self.requests = [t for t in self.requests if now - t = self.max_requests:
raise Exception("请求过于频繁,请稍后再试")
self.requests.append(now)
return self.real_service.execute(*args, **kwargs)
在线考试系统中的代理
- 检测切屏次数
- 限制复制粘贴
- 记录异常行为(如异常网络请求)
通过代理可以在不改动业务代码的前提下,实现上述监控与限制。
代理模式的价值
- 解耦:将访问逻辑与业务逻辑分离
- 增强:无感添加日志、缓存、限流等功能
- 控制:实现访问控制、权限验证
- 优化:通过懒加载和缓存提升性能
掌握代理模式后,你将在系统设计时拥有一件强大的利器。
后续预告
策略模式(Strategy Pattern)——让算法 interchangeable 的艺术。
结语
合理使用代理模式可以显著提升系统的性能与安全性,但切记不要过度设计。只有当真正需要控制访问或添加横切关注点时,才考虑引入代理。祝你在设计模式的学习之路上收获满满!