我在一个有趣的项目中遇到这个问题,我必须告诉一个类在指定的开始和结束时间(以及c的间隔)的某个时间段内执行操作。
为了论证,考虑到类A(具有我调用的API的类)必须调用类B(它调用类C,然后调用类D)和E(它们又调用类F)和G类。
A - > B - > C - > d
A - > E - > ģ
现在B类C和E类需要有关时间的上下文。我目前正在设置它,以便A类将上下文传递给B类和E类,然后它们会根据需要传递上下文。
我试图找出解决这个要求的最佳方法而不传递上下文,尽管我讨厌它,我正在考虑使用Highlander(或Singleton)或Borg模式(一个变体on Monostate)。我只想知道我对这些模式的选择。
选项1
使用传统的borg,例如:
class Borg:
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
我可以简单地在任何地方实例化这个类,并且可以访问我想要的全局状态。
选项2
monostate的另一个变体:
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而容易测试)?我似乎错过了任何缺点吗?
或者我可以坚持我现在所拥有的......根据需要传递时间。它满足松耦合要求和DI最佳实践......但它只是太麻烦了。必须有更好的方法!
答案 0 :(得分:1)
作为一般经验法则,尽量保持简单。您正在考虑针对相对简单问题的非常复杂的解决方案。
根据您提供的信息,您似乎可以在包含上下文的对象中包装执行操作的请求。然后你只是在不同的类之间传递一个对象。例如:
class OperationRequestContext:
def __init__(self, start_time, end_time):
self.start_time = start_time
self.end_time = end_time
class OperationRequest:
def __init__(self, operation, context):
self.operation = operation
self.context = context
如果有其他要求可以证明考虑更复杂的解决方案,则应指定它们。