如何以Pythonic方式优化桥接模式中try_limit属性的重复定义问题
嘿,这个问题戳中了桥接模式里很容易犯的DRY(Don't Repeat Yourself)问题——重复写属性和setter确实不够优雅,咱们来用Python的特性给你的桥接实现“瘦个身”!
先理清楚你的核心需求:
- 遵循桥接模式,解耦抽象层(Abstraction)和实现层(Implementor)
- 拥有一个可运行时动态修改的
try_limit属性,且不想在两层重复写属性逻辑
接下来给你几个Pythonic的解决方案:
方案1:用描述符封装try_limit的逻辑
描述符是Python里复用属性访问逻辑的绝佳工具,我们可以把try_limit的getter/setter逻辑封装成一个描述符类,然后在Abstraction和Implementor里直接复用:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import abc class TryLimitDescriptor: def __init__(self, default=3): self.default = default self._storage = {} def __get__(self, instance, owner): return self._storage.get(id(instance), self.default) def __set__(self, instance, value): # 可以在这里加参数校验,比如必须是正整数 if not isinstance(value, int) or value <= 0: raise ValueError("try_limit must be a positive integer") self._storage[id(instance)] = value class Abstraction(abc.ABC): try_limit = TryLimitDescriptor() def __init__(self, implementor): self.implementor = implementor # 初始化时可以直接赋值,会触发描述符的__set__ self.try_limit = 3 class Implementor(abc.ABC): try_limit = TryLimitDescriptor() @abc.abstractmethod def operation(self): pass # 测试代码 class ConcreteImplementorA(Implementor): def operation(self): print(f"Executing operation with try_limit: {self.try_limit}") abstraction = Abstraction(ConcreteImplementorA()) abstraction.try_limit = 5 print(abstraction.try_limit) # 输出5 abstraction.implementor.try_limit = 7 print(abstraction.implementor.try_limit) # 输出7
这个方案的好处是:
- 把
try_limit的校验、存储逻辑完全抽离,避免重复代码 - 抽象层和实现层各自维护自己的
try_limit值(如果需要独立的话) - 符合Python的面向对象特性,扩展性强
方案2:用共享配置对象实现“一处修改,处处生效”
如果你的try_limit是需要抽象层和实现层共享同一份值的(修改抽象层的try_limit,实现层也自动同步),那可以把try_limit封装成一个单独的配置类,让抽象层和实现层都持有这个配置对象的引用:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import abc class RetryConfig: def __init__(self, try_limit=3): self._try_limit = try_limit @property def try_limit(self): return self._try_limit @try_limit.setter def try_limit(self, value): if not isinstance(value, int) or value <= 0: raise ValueError("try_limit must be a positive integer") self._try_limit = value class Abstraction(abc.ABC): def __init__(self, implementor, retry_config=None): self.implementor = implementor self.retry_config = retry_config or RetryConfig() # 把配置对象传给实现层 self.implementor.retry_config = self.retry_config @property def try_limit(self): return self.retry_config.try_limit @try_limit.setter def try_limit(self, value): self.retry_config.try_limit = value class Implementor(abc.ABC): def __init__(self): self.retry_config = None @property def try_limit(self): if self.retry_config is None: raise ValueError("Retry config not set") return self.retry_config.try_limit @try_limit.setter def try_limit(self, value): if self.retry_config is None: raise ValueError("Retry config not set") self.retry_config.try_limit = value @abc.abstractmethod def operation(self): pass # 测试代码 class ConcreteImplementorA(Implementor): def operation(self): print(f"Executing operation with try_limit: {self.try_limit}") config = RetryConfig(3) abstraction = Abstraction(ConcreteImplementorA(), config) abstraction.try_limit = 5 print(abstraction.try_limit) # 输出5 print(abstraction.implementor.try_limit) # 输出5,自动同步
这个方案的核心是共享引用,修改配置对象的try_limit后,所有引用它的层都会拿到最新值,完美解决动态修改的需求,同时完全避免了重复代码。
方案3:让实现层代理抽象层的try_limit
如果你的实现层不需要独立的try_limit,完全依赖抽象层的配置,那可以让Implementor的try_limit直接代理到关联的Abstraction对象:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import abc class Abstraction(abc.ABC): def __init__(self, implementor): self.implementor = implementor self._try_limit = 3 # 把抽象层自身传给实现层 self.implementor.abstraction = self @property def try_limit(self): return self._try_limit @try_limit.setter def try_limit(self, value): if not isinstance(value, int) or value <= 0: raise ValueError("try_limit must be a positive integer") self._try_limit = value class Implementor(abc.ABC): def __init__(self): self.abstraction = None @property def try_limit(self): if self.abstraction is None: raise ValueError("Abstraction not associated") return self.abstraction.try_limit @try_limit.setter def try_limit(self, value): if self.abstraction is None: raise ValueError("Abstraction not associated") self.abstraction.try_limit = value @abc.abstractmethod def operation(self): pass # 测试代码 class ConcreteImplementorA(Implementor): def operation(self): print(f"Executing operation with try_limit: {self.try_limit}") abstraction = Abstraction(ConcreteImplementorA()) abstraction.try_limit = 5 print(abstraction.try_limit) # 输出5 print(abstraction.implementor.try_limit) # 输出5 abstraction.implementor.try_limit = 7 print(abstraction.try_limit) # 输出7,反向修改也生效
这个方案最简洁,适合实现层不需要独立配置的场景,完全消除了重复代码。
总结一下:
- 如果抽象层和实现层需要独立的
try_limit值,用描述符方案 - 如果需要共享同一份配置,修改同步,用共享配置对象方案
- 如果实现层完全依赖抽象层的配置,用代理属性方案
这些方案都符合Python的风格,既遵循了桥接模式的解耦原则,又避免了重复代码的问题。
内容的提问来源于stack exchange,提问作者Gaspar Cheng
相关产品推荐
相关产品推荐

