代理模式指的是通过创建一个代理来控制对原始对象的访问。代理在客户端与实际对象之间充当“中介”
特点
- 访问控制:代理对象可以控制对实际对象的访问,从而实现对访问权限的控制。
- 延迟加载:代理对象可以在实际对象被调用时才创建,从而实现延迟加载。
- 解耦: 客户端金依赖代理接口,可以与实际对象分离,从而实现解耦。
- 类型多样:虚拟代理(既延迟加载)、缓存代理(缓存对象)、远程代理(远程对象)、保护代理(权限控制)等。
模式结构
角色 | 描述 |
---|
抽象主题 (Subject) | 声明真实主题和代理主题的共同接口。客户端依赖此接口 |
真实主题 (RealSubject) | 实现抽象主题定义的接口,并提供其功能实现。实际执行业务逻辑的对象 |
代理主题 (Proxy) | 实现抽象主题定义的接口,并持有真实主题的引用。代理主题控制对真实主题的访问 |
类型 | 应用场景 |
---|
虚拟代理 | 当需要创建一个大开销的对象时,创建一个代理对象,直到需要时才创建真实的对象。 也叫延迟加载(比如在图片加载时,先加载一张占位图,当图片加载完成后再替换占位图)。 |
保护代理 | 控制权限(在客户端对真实对象进行访问前,利用代理进行权限校验等操作)。 |
缓存代理 | 缓存调用结果(为优化性能,将重复计算的值缓存起来,下次使用时直接返回缓存值)。 |
远程代理 | 本地代理远程服务(将本地的请求转发到远程的对象上)。 |
简单示例
1. 虚拟代理
python">from abc import ABC, abstractmethod
class Image(ABC):@abstractmethoddef display(self):pass
class RealImage(Image):def __init__(self, filename):self.filename = filenameself.load_from_disk()def load_from_disk(self):print(f"Loading {self.filename} from disk")def display(self):print(f"Displaying {self.filename}")
class ProxyImage(Image):def __init__(self, filename):self.filename = filenameself.real_image = None def display(self):if not self.real_image:self.real_image = RealImage(self.filename)self.real_image.display()
if __name__ == "__main__":proxy_image = ProxyImage("test_image.jpg") proxy_image.display()
2. 保护代理
python">from abc import ABC, abstractmethod
class DataBase(ABC):@abstractmethoddef query(self, sql):pass
class RealDataBase(DataBase):def query(self, sql):return f"query result: {sql}"
class ProxyDataBase(DataBase):def __init__(self, user):self.user = userself.real_db = RealDataBase()def query(self, sql):if self._check_access():return self.real_db.query(sql)else:return "access denied"def _check_access(self):return self.user == "admin"
if __name__ == "__main__":proxy_db = ProxyDataBase("admin")print(proxy_db.query("select * from user")) proxy_db = ProxyDataBase("guest")print(proxy_db.query("select * from user"))
3. 缓存代理
python">from abc import ABC, abstractmethodclass Calculate(ABC):@abstractmethoddef calculate(self, n): passclass RealCalculate(Calculate):def calculate(self, n):return n * nclass ProxyCalculate(Calculate):def __init__(self):self.cache = {}self.real_calculate = RealCalculate()def calculate(self, n):if n not in self.cache:self.cache[n] = self.real_calculate.calculate(n)return self.cache[n]if __name__ == '__main__':proxy_calculate = ProxyCalculate()for i in range(10):print(proxy_calculate.calculate(i)) for i in range(10):print(proxy_calculate.calculate(i))
4.远程代理
python">import requestsclass BaiduService:def get_data(self, question): passclass BaiduServiceProxy(BaiduService):def __init__(self):self.question = questionself.baidu_api = "www.baidu.com"def get_data(self, question):response = requests.get(self.baidu_api, params={"question": question})return response.text
if __name__ == "__main__":baidu_service = BaiduServiceProxy()data = baidu_service.get_data("如何使用代理模式")
代理模式 VS 外观模式 VS 装饰器模式 VS 适配器模式
维度 | 代理模式 | 外观模式 | 装饰器模式 | 适配器模式 |
---|
核心目的 | 控制对象访问 | 简化复杂系统接口 | 动态扩展对象功能 | 接口兼容性转换 |
结构特点 | 代理与真实对象实现相同接口 | 外观类聚合多个子系统接口 | 装饰器模式聚合被装饰对象 | 适配器模式聚合被适配对象 |
对象关系 | 代理对象持有真实对象 | 外观持有多个子系统对象 | 装饰器包裹原始对象 | 适配器持有或继承被适配对象 |
接口一致性 | 保持与真实对象接口一致 | 提供新的简化接口 | 保持与原始对象接口一致 | 转换接口以匹配目标需求 |
扩展方向 | 访问控制逻辑 | 接口简化与整合 | 功能叠加 | 接口适配 |