代码之家  ›  专栏  ›  技术社区  ›  Hilbrand Bouwkamp

最佳实践:是否在子构造函数中将子节点添加到父节点?

oop
  •  7
  • Hilbrand Bouwkamp  · 技术社区  · 15 年前

    我正在处理一些代码,这些代码将子节点添加到子节点的构造函数的父节点中。代码如下所示:

    班级:

    class Node1 {
      public Node1(Node1 parent, String name) {
         if(parent != null) {
           parent.add(this);
         }
         this.parent = parent;
      }
    
      private void add(Node1 child) {
        children.add(child);
      }
    }
    

    用途:

    Node1 parent = new Node1(null, "parent");
    Node1 child1 = new Node1(parent, "child1");
    Node1 child2 = new Node1(parent, "child2");
    

    通过这种方式实现,类的用户 Node1 不必显式地将子节点(更少的代码)添加到它的父节点,并且您已经保证子节点具有父节点。

    我个人不会这样写的,但更像是:

    class Node2 {
      public Node2(String name) {
      }
    
      public void add(Node2 child) {
        children.add(child);
        child.setParent(this);
      }
    }
    
    Node2 parent = new Node2("parent");
    Node2 child1 = new Node2("child1");
    parent.add(child1);
    Node2 child2 = new Node2("child2");
    parent.add(child2);
    

    所以我的问题是,这是一个好主意来实现它,如课堂所示 NODE1 还是有人反对这样做?或者没有争论为什么一个比另一个好?

    8 回复  |  直到 15 年前
        1
  •  11
  •   Grzenio    15 年前

    我个人不喜欢第一个示例,因为您正在添加一个还没有“准备好”的节点(因为构造函数没有完成执行)。在大多数情况下,它会很好地工作,但在极端情况下,您可能会发现非常难找到的错误。

        2
  •  2
  •   Mykola Golubyev    15 年前

    我将使用第二种情况,这样我以后就可以添加子项,但不仅是在构造函数中。

        3
  •  1
  •   Gerrie Schenck    15 年前

    我认为这两种实现都可以。

    问题更多的是您将如何使用这个类:您将首先创建一个节点列表,然后开始添加它们的关系,还是像在您的示例中一样,以有序的方式进行添加?

    第二个解决方案提供了更大的灵活性,而且如果您曾经想使用node1作为超类,那么就不需要绑定到构造函数签名。

        4
  •  1
  •   Jim T    15 年前

    我不喜欢第一种情况——仅仅通过传入就可以神奇地修改父对象——您必须阅读代码或文档才能意识到这一点。仅仅传入父对象就意味着子对象知道父对象,而不是子对象也被添加到父对象的内部列表中。

    第二个例子更好。还可以从“添加”操作返回子级,以允许操作链接,如:

    Node2 child = parent.add(new Node2());
    
        5
  •  1
  •   David Hanak    15 年前

    我认为没有理由不将这两种方法结合起来以方便使用:

    class Node1 {
      public Node1(String name, Node1 parent = null) {
        this.name = name;
        // etc., do initialization
    
        if(parent != null)
          parent.add(this);
      }
    
      private void add(Node1 child) {
        child.setParent(this);
        children.add(child);
      }
    }
    

    请注意,setParent()应该在子级已经设置了父级时引发异常,或者从前一个父级的子级列表中正确地删除自己。

        6
  •  0
  •   Patrick Peters    15 年前

    如果从TreeNode类派生节点,则会自动获得第二个实现。您可以将“自定义”TreeNode添加到常规TreeView类中。

        7
  •  0
  •   bayda    15 年前

    首先,你的第一个样本中的坏处是: 如果(父母)!{NULL){ 这项检查是必需的,因为您应该有机会创建树的根,但双状态参数看起来很难看。

    首先,您的示例不好,因为执行了隐式操作(将子级添加到传递的父级)。

        8
  •  0
  •   trshiv    15 年前

    我更喜欢实现1,只有当父节点和子节点绝对必要时。在这种情况下,客户机代码很可能忽略对node1.add(node1子级)的调用,从而导致以后的错误。

    我更喜欢实现2,否则,因为这样的用法更清晰

    Node1 parent = new Node1();
    Node1 child = new Node1();
    parent.add(child);