Python中的BaseProxy():理解代理模式与装饰器的区别与联系
代理模式和装饰器模式都属于结构型设计模式,用于在不修改原有代码的基础上添加额外的功能。然而,两者在使用方式和目的上有一些区别。
代理模式是通过引入一个代理对象来控制对真实对象的访问。代理对象拥有与真实对象相同的接口,使得客户端无需知道真实对象的存在。代理对象可以在访问真实对象之前或之后执行一些操作,如权限验证、缓存、日志记录等。代理模式常见的应用场景有远程代理、虚拟代理和保护代理等。
Python中的BaseProxy是一个抽象基类,用于创建代理对象。它提供了一个统一的接口,并定义了代理对象应该具备的方法。通过继承BaseProxy类,我们可以创建自己的代理对象,并实现相应的功能。
下面是一个使用BaseProxy创建代理对象的例子:
from abc import ABC, abstractmethod
from weakref import WeakSet
class Subject(ABC):
@abstractmethod
def request(self):
pass
class RealSubject(Subject):
def request(self):
print("RealSubject: Handling request.")
class Proxy(Subject, BaseProxy):
def __init__(self, real_subject):
super().__init__(real_subject)
self._real_subject = real_subject
def request(self):
print("Proxy: Handling request before forwarding to RealSubject.")
self._real_subject.request()
print("Proxy: Handling request after forwarding to RealSubject.")
real_subject = RealSubject()
proxy = Proxy(real_subject)
proxy.request()
在上面的例子中,我们定义了一个Subject接口和它的具体实现类RealSubject。然后,我们创建了一个代理类Proxy,并将真实对象RealSubject传递给它的构造方法。代理类通过继承BaseProxy类,实现了真实对象相同的接口,并在代理方法中调用真实对象的方法。
当我们调用代理对象的request方法时,代理对象会在调用真实对象的方法之前和之后分别输出相应的信息,实现了对真实对象的控制和增强。
而装饰器模式是通过在不修改原有代码的情况下,动态地给对象添加额外的功能。装饰器模式使用装饰器函数来包装函数或类,从而实现功能的增加和组合。通常情况下,装饰器函数会接收一个函数作为参数,并返回一个新的函数,新的函数会在调用原函数之前或之后执行一些操作。
下面是一个使用装饰器模式给函数添加日志记录功能的例子:
import functools
import logging
def logged(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"Calling {func.__name__}")
result = func(*args, **kwargs)
logging.info(f"{func.__name__} returned {result}")
return result
return wrapper
@logged
def add(x, y):
return x + y
result = add(2, 3)
在上面的例子中,我们定义了一个logged装饰器函数,它接收一个函数作为参数,并返回一个新的函数。新的函数在调用被装饰的函数之前和之后分别输出相应的日志信息。
然后,我们使用@logged装饰器将add函数装饰起来。当我们调用add函数时,装饰器函数会在调用add函数之前和之后分别输出日志信息,实现了对add函数的增强。
总结起来,代理模式适用于在不能或不想直接访问某个对象时,使用代理对象来间接访问。而装饰器模式适用于在不修改原有代码的情况下,给对象添加额外的功能。两者的区别在于代理模式通过引入一个代理对象来控制对真实对象的访问,而装饰器模式通过包装函数来动态地添加功能。
同时,代理模式和装饰器模式也可以相互结合使用。例如,我们可以使用代理模式创建一个装饰器对象,使其具备对真实对象的访问和功能增强的能力。这样可以在保持原有代码不变的基础上,随时动态地添加或移除装饰器,实现额外的功能增强。
