代理模式深度指南:控制对象访问的艺术
在软件开发中,我们经常需要控制对某个对象的访问。代理模式提供了一种优雅的解决方案,通过引入一个代理对象来间接访问真实对象,从而实现访问控制、延迟加载、功能增强等多种高级特性。
什么是代理模式?
代理模式(Proxy Pattern)是一种结构型设计模式,它为另一个对象提供一个替身或占位符,以控制对这个对象的访问。代理对象可以在不改变真实对象接口的前提下,执行额外的逻辑。
核心组成
- 抽象主题(Subject):真实对象和代理对象的共同接口
- 真实主题(Real Subject):被代理的真实对象
- 代理(Proxy):持有真实对象的引用,负责控制和管理访问
代理模式的类型
1. 远程代理
为位于不同地址空间的对象提供本地代表。
class RemoteProxy:
def __init__(self, host, port):
self.host = host
self.port = port
self._stub = None
def _connect(self):
if not self._stub:
self._stub = self._create_stub()
return self._stub
def request(self, method, *args):
stub = self._connect()
return stub.invoke(method, *args)
2. 虚代理
延迟加载大型对象,只在真正需要时才创建真实对象。
class VirtualProxy:
def __init__(self, file_path):
self.file_path = file_path
self._real_object = None
@property
def real_object(self):
if self._real_object is None:
print("正在加载大型对象...")
self._real_object = HeavyObject(self.file_path)
return self._real_object
def get_data(self):
return self.real_object.get_data()
3. 保护代理
控制对真实对象的访问权限。
class ProtectionProxy:
def __init__(self, real_subject, user_role):
self.real_subject = real_subject
self.user_role = user_role
def request(self):
if self.user_role == "admin":
return self.real_subject.request()
return "权限不足,拒绝访问"
4. 智能引用
在访问对象时执行额外的操作,如计数、缓存等。
class SmartProxy:
def __init__(self, real_subject):
self.real_subject = real_subject
self.access_count = 0
def request(self):
self.access_count += 1
print(f"对象被访问了 {self.access_count} 次")
return self.real_subject.request()
实际应用场景
场景一:图片懒加载
from typing import Optional
class Image:
def __init__(self, path: str):
self.path = path
self._data: Optional[bytes] = None
def load(self) -> bytes:
if self._data is None:
print(f"Loading image from {self.path}...")
with open(self.path, rb) as f:
self._data = f.read()
return self._data
def display(self):
print(f"Displaying image: {self.path}")
class ImageProxy:
def __init__(self, path: str):
self.path = path
self._image: Optional[Image] = None
def display(self):
if self._image is None:
self._image = Image(self.path)
self._image.display()
# 使用
proxy = ImageProxy("photo.jpg")
proxy.display() # 首次显示时才加载
场景二:API 限流保护
import time
from collections import deque
class RateLimiter:
def __init__(self, max_requests: int, window_seconds: int):
self.max_requests = max_requests
self.window_seconds = window_seconds
self.requests = deque()
def allow(self) -> bool:
now = time.time()
while self.requests and self.requests[0] < now - self.window_seconds:
self.requests.popleft()
if len(self.requests) < self.max_requests:
self.requests.append(now)
return True
return False
class APIService:
def __init__(self):
self.data = {"users": [1, 2, 3]}
def get_users(self):
return self.data["users"]
class APIServiceProxy:
def __init__(self, service: APIService, limiter: RateLimiter):
self.service = service
self.limiter = limiter
def get_users(self):
if self.limiter.allow():
return self.service.get_users()
raise Exception("Rate limit exceeded")
场景三:数据库连接池
class DatabaseConnection:
def __init__(self):
print("创建新的数据库连接...")
time.sleep(0.1)
def query(self, sql: str):
return f"Result: {sql}"
class ConnectionPool:
def __init__(self, max_size: int = 5):
self.max_size = max_size
self.available = []
self.in_use = []
def acquire(self) -> DatabaseConnection:
if self.available:
conn = self.available.pop()
elif len(self.in_use) < self.max_size:
conn = DatabaseConnection()
else:
raise Exception("No available connections")
self.in_use.append(conn)
return conn
def release(self, conn: DatabaseConnection):
if conn in self.in_use:
self.in_use.remove(conn)
self.available.append(conn)
代理模式 vs 装饰器模式
| 特性 | 代理模式 | 装饰器模式 |
|---|---|---|
| 目的 | 控制访问 | 动态添加功能 |
| 关系 | 代理与真实对象通常有相同接口 | 装饰器包装对象 |
| 创建时机 | 可在运行时创建真实对象 | 通常在设计时确定 |
| 透明性 | 对客户端透明 | 透明添加功能 |
总结
代理模式是一种强大的设计模式,它能够帮助我们:
- ✅ 控制访问:实现权限验证、限流等
- ✅ 延迟加载:提高系统性能
- ✅ 功能增强:在访问前后执行额外操作
- ✅ 解耦:分离访问逻辑和业务逻辑
在实际开发中,代理模式广泛用于缓存、远程调用、懒加载、事务管理等场景。理解代理模式,能够帮助你设计出更加优雅和高效的架构。
推荐阅读:
- 《设计模式》 - Erich Gamma 等著
- Clean Code - Robert C. Martin 著
如果你喜欢这篇文章,欢迎关注我的更多内容!🚀
Top comments (0)