Python Borg多重继承和共享状态

时间:2016-07-19 05:12:45

标签: python inheritance design-patterns

我在一个有趣的项目中遇到这个问题,我必须告诉一个类在指定的开始和结束时间(以及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模式(虽然类包装器很酷)。

  1. 常规的Borg模式必须经过多次实例化,以至于存储一组值似乎太多了。

  2. 在实例化类时,Borg mixin被实例化多次。我不知道如何更难测试。

  3. 包装器非常通用,相对容易测试。理论上,因为它是一个函数闭包,我应该能够改变东西,但它基本上变成了一个单例(这看起来太复杂了,在这种情况下我也可以使用常规的单例模式)。另外,传递函数句柄会使目的失败。

  4. 除了这三种方式,还有其他方法吗?任何更好的方法(博格似乎没有因为没有DI而容易测试)?我似乎错过了任何缺点吗?

    或者我可以坚持我现在所拥有的......根据需要传递时间。它满足松耦合要求和DI最佳实践......但它只是太麻烦了。必须有更好的方法!

1 个答案:

答案 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

如果有其他要求可以证明考虑更复杂的解决方案,则应指定它们。