在构造函数中修改其他对象的状态:设计no-no?

问题描述:

我重构一些代码,发现这个(简化当然,但总的想法):在构造函数中修改其他对象的状态:设计no-no?

class Variable: 
    def __init__(self): 
     self.__constraints = [] 

    def addConstraint(self, c): 
     self.__constraints.append(c) 

class Constraint: 
    def __init__(self, variables): 
     for v in variables: 
      v.addConstraint(self) 

该约束的构造函数修改其他对象的状态,而不是它自己的味道有点时髦给我的事实。其他人认为 - 这是好的,还是重构的主要候选者?

编辑:我关心的不是父/子关系,而是它在构造函数中而不是在单独的方法中进行关联。

+0

在初始化做它(不是构造函数,这将是法'__new__' - 由你运行'__init__'的实例已建成的时候,虽然尚未初始化)保证类不变量,例如“每个约束总是存在于一定数量的变量中“。否则将意味着据称“初始化”约束实际上不符合类不变式;为什么你会以任何方式想到这样的情况?请看我的答案更多的例子...! – 2009-10-15 18:01:08

我同意你的意见。这是倒退。为什么会有一些很好的理由,但是编程不清楚,如果脚迟早出现,它可能会咬人。

我把它看作一种自我注册模式。 “你好我是新来的,请允许我加入。”

我可能更喜欢使用不同名称的方法,以便目的更清晰,但我确实非常喜欢这种方法。

+2

国际海事组织做到这一点非常好。在构造函数中进行自注册而不是另一种方法意味着a)无法忘记它,并且b)做两次的可能性更少 – 2009-10-15 15:44:27

当您有两个密切相关的对象(即只有其中一个没有意义)时,这是常用的。最常见的情况是:父母的孩子关系。将子项添加到父项(即parent.children.append(child))时,通常也会更新child.parent指针。

+0

我知道这是一个常见的设计,这就是为什么我要重构它。区别在于它不是在一个单独的方法中完成的,它是通过将父项传递给子构造函数并在构造函数中执行更新来完成的。 – tbocek 2009-10-15 15:28:28

+0

在构造函数或方法中做这件事情我看不出有什么大不同。构造函数只是一次被调用的特殊方法。所以如果孩子没有父母没有意义,我会添加孩子的构造函数来将所有的代码放在一个地方。 – 2009-10-15 15:59:48

我个人并不反对这一点,但...

我会选择一个使用模式,并坚持下去。在你的情况,因为变量已经有一个干净的addConstraint方法,我的首选是使用它。否则,您需要添加良好的检查以防止用户构建约束,然后将其添加到Variable类(从而将其添加两次)。

这就是说,像一个约束,但我可能不会这样做。约束似乎是一个来自变量的概念独立实体。我看不出任何合乎逻辑的理由,相同的约束不能添加到两个单独的变量中。我只是让它构建你的约束,然后手动添加它们,特别是出于这个原因。

+0

如果一个约束可以明显地“附加到没有变量”(这似乎很少或根本没有意义),那么它可能是合理的建立它作为独立的;但是在常见的情况下,给定的习惯用法更好,其中一个约束总是附加到1+个变量上('__init__'中的'assert variables'将使晶体清晰,但如果'variables'可以是任何可迭代的,那么assert可以“消费”它,给定的代码仍然完美)。 – 2009-10-15 18:04:46

我完全同意@ djna的回答,即特定的用例是完全合法的 - 在这里,它是一个对象的例子,需要在“出生时”注册一组指定的注册表。

一个非常尖锐和极其常见的子表达式将是一个观察者对象,严格地说是为了观察给定的observable而存在 - 完全可以将observable传递给观察者的初始化器,并且确切地说是正确的方式来确保如果仅在完成初始化之后才进行注册,那么这个观察者类的“类不变”实例总是与确切的一个可观察对象相关联“,这在出生时不会建立。

其他类似情况包括例如必须始终存在于容器窗口内的小部件对象:除非让小部件将父母作为初始化器参数并告诉父亲“嗨,我是你的新孩子!“。

至少在那些很多情况下,您可以想象强制父对象或可观察对象具有创建和注册新对象的方法。在诸如此类的许多案例中,该方法的内在性质有所揭示 - 因为约束必须用多个变量进行登记,因此要求其中任何一个特定人员创建“反对谷物”约束。您提供的代码是完全自然的。

仅适用于那些无法被诬陷为新对象的情况下“enregistering本身”我会觉得有些怀疑(也有一些其他合法的,如对象创建和出生enregistering其他辅助的,但他们远不及普通)。