结构型——代理模式

发布于:2025-03-25 ⋅ 阅读:(23) ⋅ 点赞:(0)

结构型——代理模式

代理模式指的是通过创建一个代理来控制对原始对象的访问。代理在客户端与实际对象之间充当“中介”

特点

  • 访问控制:代理对象可以控制对实际对象的访问,从而实现对访问权限的控制。
  • 延迟加载:代理对象可以在实际对象被调用时才创建,从而实现延迟加载。
  • 解耦: 客户端金依赖代理接口,可以与实际对象分离,从而实现解耦。
  • 类型多样:虚拟代理(既延迟加载)、缓存代理(缓存对象)、远程代理(远程对象)、保护代理(权限控制)等。

模式结构

角色 描述
抽象主题 (Subject) 声明真实主题和代理主题的共同接口。客户端依赖此接口
真实主题 (RealSubject) 实现抽象主题定义的接口,并提供其功能实现。实际执行业务逻辑的对象
代理主题 (Proxy) 实现抽象主题定义的接口,并持有真实主题的引用。代理主题控制对真实主题的访问

代理模式类型

类型 应用场景
虚拟代理 当需要创建一个大开销的对象时,创建一个代理对象,直到需要时才创建真实的对象。
也叫延迟加载(比如在图片加载时,先加载一张占位图,当图片加载完成后再替换占位图)。
保护代理 控制权限(在客户端对真实对象进行访问前,利用代理进行权限校验等操作)。
缓存代理 缓存调用结果(为优化性能,将重复计算的值缓存起来,下次使用时直接返回缓存值)。
远程代理 本地代理远程服务(将本地的请求转发到远程的对象上)。

简单示例

1. 虚拟代理

from abc import ABC, abstractmethod

# 抽象主题
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"Loading {self.filename} from disk")

    def display(self):
        print(f"Displaying {self.filename}")

# 代理主题(控制加载时机)
class ProxyImage(Image):
    def __init__(self, filename):
        self.filename = filename
        self.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")             # Loading test_image.jpg from disk
    # 当需要展示时,实际去加载显示
    proxy_image.display()                                  # Displaying test_image.jpg

2. 保护代理

from abc import ABC, abstractmethod

# 抽象主题
class DataBase(ABC):
    @abstractmethod
    def 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 = user
        self.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"))         # query result: ....
    proxy_db = ProxyDataBase("guest")
    print(proxy_db.query("select * from user"))         # access denied

3. 缓存代理

from abc import ABC, abstractmethod

class Calculate(ABC):
    @abstractmethod
    def calculate(self, n): pass

class RealCalculate(Calculate):

    def calculate(self, n):
        return n * n

class 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.远程代理

import requests

class BaiduService:
    def get_data(self, question): pass

class BaiduServiceProxy(BaiduService):
    def __init__(self):
        self.question = question
        self.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 适配器模式

维度 代理模式 外观模式 装饰器模式 适配器模式
核心目的 控制对象访问 简化复杂系统接口 动态扩展对象功能 接口兼容性转换
结构特点 代理与真实对象实现相同接口 外观类聚合多个子系统接口 装饰器模式聚合被装饰对象 适配器模式聚合被适配对象
对象关系 代理对象持有真实对象 外观持有多个子系统对象 装饰器包裹原始对象 适配器持有或继承被适配对象
接口一致性 保持与真实对象接口一致 提供新的简化接口 保持与原始对象接口一致 转换接口以匹配目标需求
扩展方向 访问控制逻辑 接口简化与整合 功能叠加 接口适配

网站公告

今日签到

点亮在社区的每一天
去签到