4 回答

TA贡献1784条经验 获得超2个赞
Martin Fowler,Kent Beck等作者的《重构:改进现有代码的设计》一书中描述了称为“双向关联”的问题。在书中解决问题的方式是通过为一个类分配对另一个类的完全控制权。首先,您需要确定此处必须控制哪个类。我认为,在您的情况下,孩子应该受控制,这与现实世界的工作方式背道而驰。然后,您需要允许控制器访问受控对象的私有成员。在C ++中,您可以通过使一个类成为另一个类的“朋友”来解决此问题。在具有真正隐私权的其他语言中,您可以创建一个公共访问器方法,并在文档中明确声明该方法只能由一个类使用。但是在Python中,您不受这种方式的限制。考虑以下代码:
class Child(object):
def __init__(self, parent=None):
self._parent = None
self.set_parent(parent)
def set_parent(self, parent):
# Remove self from old parent's children
if self._parent:
self._parent._children.remove(self)
# Set new parent
self._parent = parent
# Add self to new parent's children
if self._parent:
self._parent._children.append(self)
class Parent(Child):
def __init__(self, parent=None):
super(Parent, self).__init__(parent)
self._children = []
def add_child(self, child):
if child not in self._children:
child.set_parent(self)
def remove_child(self, child):
if child in self._children:
child.set_parent(None)
c1 = Child()
c2 = Child()
p1 = Parent()
p2 = Parent()
p1.add_child(c1)
p1.add_child(c2)
print "1:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children
p2.add_child(c1)
print "2:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children
c1 = Child()
c2 = Child()
p1 = Parent()
p2 = Parent()
c1.set_parent(p1)
c2.set_parent(p1)
print "3:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children
c1.set_parent(p2)
print "4:"
print "c1._parent", c1._parent
print "c2._parent", c2._parent
print "p1._children", p1._children
print "p2._children", p2._children

TA贡献1826条经验 获得超6个赞
parent.add_child(child)
和child.set_parent(parent)
(应该是)相同的操作。让其中一个委托给另一个,或者让两个委托给第三个方法,或者只是删除其中一个。这将使事情更容易推理。
解决此问题的快速而肮脏的_add_child
方法是添加一个孩子而不触碰孩子的parent
属性的方法。您set_parent
可以使用它来避免无限递归。但是,类似之类的方法_add_child
或您当前使用的方法remove_child
容易出错,因为它们破坏了双向链接的对称性。一方对关系的看法与另一方暂时不同,很容易使双方不同步。这将会是清洁的落实add_child
和set_parent
在方法方面,这种关系的更新双方的一次。
不请自来的额外建议:请勿使用双下划线前缀。它不会阻止类外部的代码访问该属性,无论如何,您都不应尝试在Python中阻止这种行为。只需使用一个下划线,表明它不属于该类的公共API。
添加回答
举报