我在一个树状结构中工作,其中每个父节点可以包含几个子节点,每个子节点只能有一个父节点,这与文件系统中的目录结构非常相似。
我已经做了很多这样的工作,并且有很多不同的方法来解决鸡和蛋的问题,比我现在要和大家分享的要多,但是我想知道是否有一个更不太理想的通用设计模式,我到目前为止一直忽略它来解决它。
现在,问题是,当您将父节点设置为子节点时,父节点必须将此新节点添加到其内部子节点列表中,并且当您将子节点添加到父节点时,子节点必须更新其父节点,这一切都是为了保持树的一致性,否则您可能会导致父节点的子节点不能识别为父节点,反之亦然……
让我们以一个例子(我将使用JAVA)来看看,因为代码中显示的代码问题比段落中解释的要好:

class Node {
    private Node parent;
    private ArrayList<Node> sons=new ArrayList<Node>();

    public void setParent(Node parent) {
        this.parent = parent;
        parent.addSon(this);
    }

    public void addSon(Node son) {
        this.sons.add(son);
        son.setParent(this);
    }

}

好吧,为了简单起见,这是最简单的形式,不过还有其他事情要处理(例如,从以前的父级移除子级)。我敢肯定你已经看到了我们这里的递归问题。
一个或多或少显而易见的方法是在运行时检查子进程是否已经将其分配为父进程,因此我将这些方法重写为:
    public void addSon(Node son) {
        this.sons.add(son);
        if (son.parent != this)
            son.setParent(this);
    }

但我想知道是否有更好的方法来解决这个问题例如,另一种可以节省一些冗余调用的方法是使用静态方法,例如:
 class Node {
    private Node parent;
    private ArrayList<Node> sons=new ArrayList<Node>();

    public static assignSon(Node parent, Node son) {
        parent.sons.add(son);
        son.parent = parent;
    }
}

因此,只要assignSon是唯一一个可以用来将儿子和父亲联系起来的方法,这就解决了鸡和蛋之间的问题,但从外部使用它也不那么直观,而且您必须编写更多的代码,您知道,在您可以做类似的事情之前,在哪里:
son.setParent(parent);

或者
parent.addSon(son);

你现在要写:
Node.assignSon(parent, son);

没什么大不了的,但是好吧,随便吧。如果你知道解决这个问题的最佳方法,并且你想与这个社区分享,我将非常感谢!
蒂亚!

最佳答案

我将使用与@uoyilmaz相同的代码,但请记住更新旧的父级(如果已经存在),否则如果您将已分配给其他人的儿子分配给其他人,您将得到一些不一致的结果。
例如,如果来自此树:

   a
 / | \
b  c  d

你移动d作为b的儿子
  a
 / \
b   c
|
d

a仍将引用d节点。
所以也许这样的事情应该管用:
class Node {
    private Node parent;
    private ArrayList<Node> sons=new ArrayList<Node>();

    private void setParent(Node parent) {
        this.parent = parent;
    }

    public void addSon(Node son) {
        if(!this.sons.contains(son)) {
            this.sons.add(son);

            if(son.parent != null) {
                son.parent.sons.remove(son);
            }

            son.setParent(this);
        }
    }
}

07-24 09:51