我该如何解决这个循环依赖?

时间:2015-07-17 08:38:02

标签: python import python-import

鉴于这些类形成了一个灵活的树:

class ElementBase(object):
    pass

class Form(ElementBase):
    pass

class TextInput(ElementBase):
    pass

class DateTimeInput(ElementBase):
    pass

class NumberInput(ElementBase):
    pass

如果元素在Form中,它应该能够找到所述表单。由于这是元素的一种非常常见的情况(在这种情况下,大约三分之一的元素继承自ElementBase需要这样做),这个特性属于ElementBase。这直接导致循环依赖,因为我提出的唯一方法是:

def get_parent_form(self, compo):
    if isinstance(compo, Form):
        return compo
    if not hasattr(compo, 'container_compo'):
        return None
    return self.get_parent_form(compo.container_compo)

我该如何正确地做到这一点?

1 个答案:

答案 0 :(得分:1)

@jonrsharpe在评论中谈到了这一点,但我会详细说明:

您的结构as-is作为对象层次结构没有意义。您的表单部分由composition个* Input对象组成,所有这些对象都可以通过Elements的公共属性组合在一起并具有Form父级。这也是表单本身的可区分行为,因为(至少我可以告诉你)你的表单不能嵌套在彼此之内,并且可以与其他ElementBase继承对象区分开来,因为你的帐户中只有三分之一表现出这种行为。

因为你有一大群对象都以明显可分的方式表现出共同的行为,所以最合理的做法是实现一个实现该行为的父类并拥有必要的输入继承来自那个班级。

然后你有ElementBase - > Form和ElementBase - >输入 - > TextInput等

这不是“hacky”,因为您可以清楚地描述此行为并对显示它的类进行逻辑分组。我认为,当从它继承的2/3类不显示该行为时,尝试将此逻辑强行插入到ElementBase中会更加 more hacky。

另请注意,如果您按照在评论中谈到的那样执行了FormInput,那么FormInput 将不会驻留在Form的模块中,因为它描述了自己刚刚发生的对象组与表格有关系。

有些方法可以重写整个系统,以允许任意Form-in-Form嵌套等等,但这可能最终会产生一个完全不同的API。 您现在可能想要考虑的一件事就是,为什么您要让您的子元素首先访问其父表单。作为一般的OOP规则,您真的只希望您的父母成为访问他们的孩子,因为否则你的对象通常不正确encapsulating他们的特定行为和属性。在你的例子中,我只希望TextInput“拥有”其中的字符,那么为什么它需要在Form中操作呢?为什么Form不能在需要时从输入中获取文本?

您可能希望查看其他一些与您的项目类似的代码库,以获取有关如何建模数据的想法。我建议Django-REST-Framework作为表单输入(在他们的例子中,Serializer-Field)实现的一个特别好的例子。他们的Serializer与Forms非常相似,但由于他们在访问数据时非常谨慎,因此可以让Serializers继承自Fields,从而使它们可以任意嵌套。这也是非常漂亮的代码。