代理模式Proxy Pattern, since 2024-06

2024-06-01  本文已影响0人  Mc杰夫

(2024.06.02 Sun)
代理模式是结构模式(structural pattern)的一种,为真实对象提供了代替用的接口,扮演中介(intermediary)、代理(surrogate)的角色。代理接收到对真实对象的访问/请求,执行与真实对象相同的功能和动作,可加入额外的功能且不需要修改真实对象。

使用场景

若干可能使用代理模式的场景:

案例

概念案例 conceptual example

该案例用于解释

首先定义一个Subject接口,声明RealSubjectProxy两个类的基本操作。只要使用了该接口的RealSubject类在客户端可用,用户就可以使用Proxy类代替RealSubject类。

from abc import ABC, abstractmethod

class Subject(ABC):
    @abstractmethod
    def request(self) -> None:
        pass

接下来定义RealSubject类,该类中包含核心业务逻辑。而Proxy类与RealSubject有相同接口,可以解决RealSubject中或反应慢或敏感的问题,比如矫正输入数据等。Proxy中最常见的应用包括惰性加载(lazy loading),缓存,控制连接(controlling the access),记录日志等。Proxy可执行应用中的一个,并根据结果进行RealSubject相同的方法

class RealSubject(Subject):
    def request(self) -> None:
        print("RealSubject: Handling request.")

class Proxy(Subject):
    def __init__(self, real_subject: RealSubject) -> None:
        self._real_subject = real_subject

    def request(self) -> None:
        if self.check_access():
            self._real_subject.request()
            self.log_access()

    def check_access(self) -> bool:
        print("Proxy: Checking access prior to firing a real request.")
        return True

    def log_access(self) -> None:
        print("Proxy: Logging the time of request.", end="")

下面是客户单代码,客户端通过Subject接口和所有对象交互。

def client_code(subject: Subject) -> None:
    subject.request()

下面运行这些代码

if __name__ == "__main__":
    print("Client: Executing the client code with a real subject:")
    real_subject = RealSubject()
    client_code(real_subject)
    print("Client: Executing the same client code with a proxy:")
    proxy = Proxy(real_subject)
    client_code(proxy)

运行结果如下

Client: Executing the client code with a real subject:
RealSubject: Handling request.
Client: Executing the same client code with a proxy:
Proxy: Checking access prior to firing a real request.
RealSubject: Handling request.
Proxy: Logging the time of request.

数据库缓存 Caching Proxy for Database Queries

(2024.06.03 Mon at KLN)
该案例中,CacheProxy设计成为客户端与数据库对象RealDatabaseQuery之间的媒介,检测查询结果是否已经进入缓存,并在规定的缓存周期内(specified cache duration)返回缓存结果。

如果缓存已经过期或结果不在缓存中,CacheProxy代理从RealDatabaseQuery中执行查询,将结果推入缓存,并返回给客户端。CacheProxy降低了数据库服务器的负载,通过缓存的方式加速了数据查询的速度和效率。

首先定义数据库接口DatabaseQuery,定义了抽象类的基本方法。

from abc import ABC, abstractmethod
import time

class DatabaseQuery(ABC):
    @abstractmethod
    def execute_query(self, query: str):
        pass

定义数据库类RealDatabaseQuery

class RealDatabaseQuery(DatabaseQuery):
    def execute_query(self, query: str):
        print(f"Execute query: {query}")
        # do something 
        return f"results for query: {query}"

定义数据查询的代理CacheProxy

class CacheProxy(DatabaseQuery):
    def __init__(self, real_database_query: DatabaseQuery, cache_duration: int):
        self._real_database_query = real_database_query
        self._cache_duration = cache_duration
        self._cache = {}

    def execute_query(self, query: str) -> Union[str, int]:
        if query in self._cache and time.time() - self._cache[query]["timestamp"] <= self._cache_duration:
            # results in cache
            print(f"Returning cached results: {query}")
            return self._cache[query]["result"]
        else:
            # perform query in RealDatabaseQuery
            result = self._real_database_query.execute_query(query)
            self._cache[query] = {"result": result, "timestamp": time.time()}
            return result

客户端代码

if __name__ == "__main__":
    real_database_query = RealDatabaseQuery()
    cache_proxy = CacheProxy(real_database_query, 3) 
    # query for the 1st time, will query real database directly
    print(cache_proxy.execute_query("SELECT * FROM table_1")
    print(cache_proxy.execute_query("SELECT * FROM table_2")
    time.sleep(2)
    # query for the 2nd time, will read cache which with shorter response time
    print(cache_proxy.execute_query("SELECT * FROM table_1")
    print(cache_proxy.execute_query("SELECT * FROM table_2")

性能监控代理 Monitoring Proxy for performance metrics

(2024.06.05 Wed)
该代理用于对真实对象的执行性能做统计,记录日志且不会影响真实对象的功能。该代理可惰性实例化(lazily instantiate)真实对象,确保系统资源被保留到对象运行之时。

定义接口

from abc import ABC, abstractmethod
from datetime import datetime

class Subject(ABC):
    @abstractmethod
    def perform_operation(self):
        pass

定义真实对象

class RealSubject(Subject):
    def perform_operation(self):
        """
        The Real Subject's method representing a costly operation.
        """
        print("RealSubject: Performing a costly operation...")

定义代理对象

class MonitoringProxy(Subject):
    def __init__(self):
        self._real_subject = None

    def perform_operation(self):
        """
        The Proxy's method, which monitors and adds performance metrics.
        Lazily instantiates the Real Subject on the first call.
        """
        if self._real_subject is None:
            print("MonitoringProxy: Lazy loading the RealSubject...")
            self._real_subject = RealSubject()
        
        start_time = datetime.now()
        print(
          f"MonitoringProxy: Recording operation start time - {start_time}"
        )
        
        # Delegate the operation to the Real Subject
        self._real_subject.perform_operation()
        
        end_time = datetime.now()
        execution_time = end_time - start_time
        print(f"MonitoringProxy: Recording operation end time - {end_time}")
        print(
          f"MonitoringProxy: Operation executed in {execution_time} seconds"
        )

定义客户端

if __name__ == "__main__":
    monitoring_proxy = MonitoringProxy()
    monitoring_proxy.perform_operation()

当代理对象调用perform_operation方法时,MonitoringProxy记录运行的开始和结束时间,以计算总运行时间,且无需改变RealSubject对象的行为。

其他应用案例

Reference

1 medium,Design Patterns in Python: Proxy, The Powerful Surrogate, by Amir Lavasani
2 Refactoring Guru, Proxy in Python

上一篇下一篇

猜你喜欢

热点阅读