如何将父母与子女彼此联系起来?

有两个简单的类;一个仅具有parent属性,一个同时具有parent和children属性。这意味着,一个既parent和children继承了一个只parent。


这是只有parent属性的类。之所以称呼它是Child因为它只能是一个孩子,而不能是父母。我将使用一种方法set_parent()使其更加清晰,但在实际代码中将使用setter。


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.remove_child(self)

        # Set new parent

        self.__parent = parent

        # Add self to new parent's children

        if self.__parent:

            self.__parent.add_child(self)

该代码非常合理,并且似乎可以正常工作。这是,如果Parent该类看起来像这样简单:


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:

            self.__children.append(child)


    def remove_child(self, child):

        if child in self.__children:

            self.__children.remove(child)

不过,我希望能够调用my_parent.add_child(my_child)和具有my_child的父属性设置为my_parent同时消除my_child从它的老父母的孩子。


我似乎无法弄清楚如何实际设计的代码,一切我尝试将变成之间的无限循环set_parent()和add_child()或remove_child()。


我知道这个网站并不意味着其他人可以为我编写代码,但是至少有人可以给我一些提示吗?我的大脑无法解决这个问题,我已经连续思考了30分钟,却没有做任何事情。帮助赞赏!


人到中年有点甜
浏览 220回答 4
4回答

心有法竹

你在做什么都是胡说八道。只是让他们一类和使用或者 add_child()和remove_child() 或 set_parent(),但不能同时使用。

一只斗牛犬

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._parentprint "c2._parent", c2._parentprint "p1._children", p1._childrenprint "p2._children", p2._childrenp2.add_child(c1)print "2:"print "c1._parent", c1._parentprint "c2._parent", c2._parentprint "p1._children", p1._childrenprint "p2._children", p2._childrenc1 = Child()c2 = Child()p1 = Parent()p2 = Parent()c1.set_parent(p1)c2.set_parent(p1)print "3:"print "c1._parent", c1._parentprint "c2._parent", c2._parentprint "p1._children", p1._childrenprint "p2._children", p2._childrenc1.set_parent(p2)print "4:"print "c1._parent", c1._parentprint "c2._parent", c2._parentprint "p1._children", p1._childrenprint "p2._children", p2._children

跃然一笑

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

相关分类

Python