【发布时间】:2016-07-19 05:12:44
【问题描述】:
我在一个有趣的项目中遇到了这个问题,我必须告诉一个类在指定的开始和结束时间(以及 c 的间隔)的特定时间段内执行操作。
为了论证,请考虑 A 类(具有我调用的 API 的类)必须调用 B 类(它调用 C 类,然后又调用 D 类)和 E(它又调用 F 类和 G 类)。
A -> B -> C -> D
A -> E -> G
现在 B C 和 E 类需要关于时间的上下文。我目前已经进行了设置,以便 A 类将上下文传递给 B 类和 E 类,然后它们根据需要依次传递上下文。
我正在尝试找出在不传递上下文的情况下解决此要求的最佳方法,尽管我很讨厌它,但我正在考虑使用 Highlander(或 Singleton)或 Borg 模式(Monostate 的一种变体) )。我只是想知道我对这些模式的选择。
选项 1
使用传统的博格,例如:
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
我可以简单地在任何地方实例化这个类,并可以访问我想要的全局状态。
选项 2
单态的另一种变体:
class InheritableBorg:
__time = (start, end, interval)
def __init__(self):
pass
@property
def time(self):
return __time
@time.setter
def time(self, time):
__time = time
理论上,这将允许我通过以下方式进行扩展:
class X(InheritableBorg):
pass
为了扩展,我会这样做:
class NewInheritableBorg(InheritableBorg):
__time = (0, 0, 'd')
然后理论上我可以利用多重继承,然后就可以一次访问多个 borgs,例如:
class X(InheritableBorg1, InheritableBorg2):
pass
我什至可以选择性地覆盖某些东西。
选项 3
如果可能的话,使用一个包装的嵌套函数作为类装饰器/包装器。但是,我只能使用一次,并且需要传递函数句柄。这是基于代理/委托理念的混合。
这在我的脑海中并不具体,但本质上是这样的:
def timer(time)
def class_wrapper(class_to_wrap):
class Wrapper(class_to_wrap):
def __init__(self, *a, **kw):
super().__init__(*a, **kw)
def get_time(self):
return time
return Wrapper
return class_wrapper
@timer(time)
class A_that_needs_time_information:
pass
I think that might work... BUT I still need to pass the function handle.
总结
所有这些都是可能的解决方案,我倾向于多继承 Borg 模式(尽管类包装器很酷)。
常规的 Borg 模式必须实例化很多次,以至于仅存储一组值似乎开销太大。
Borg mixin 的实例化次数与类的实例化次数一样多。我不明白测试会变得多么困难。
包装器是超通用的,并且相对容易测试。从理论上讲,因为它是一个函数闭包,所以我应该能够改变一些东西,但它本质上变成了一个单例(在这种情况下,这似乎太复杂了,我不妨只使用常规的单例模式)。此外,传递函数句柄会违背目的。
除了这三种方法,还有其他方法吗?有什么更好的方法(因为没有 DI,Borg 似乎不容易测试)?有没有我似乎遗漏的缺点?
或者,我可以坚持我现在拥有的……根据需要消磨时间。它满足松散耦合要求和 DI 最佳实践……但它太麻烦了。必须有更好的方法!
【问题讨论】:
标签: python inheritance design-patterns