我正在使用一些代码,在子代的构造函数中将子节点添加到它的父节点。代码看起来像这样:
类别:
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
类所示实现它是一个好主意,还是有任何反对意见?或者没有争论为什么一个人比另一个好?
答案 0 :(得分:11)
我个人不喜欢第一个例子,因为你正在添加一个尚未“准备好”的节点(因为构造函数没有完成执行)。在大多数情况下它会正常工作,但在极端情况下你可能会遇到很难找到的错误。
答案 1 :(得分:2)
我会使用第二种情况,因为我以后可以添加子项,但不仅仅是在构造函数中。
答案 2 :(得分:1)
我认为两种实现都没问题。
问题是你将如何使用这个类:你会先创建一个节点列表然后开始添加他们的关系,还是会以有序的方式进行,比如你的例子?
第二种解决方案提供了更大的灵活性,如果您想将Node1用作超类,则不必绑定构造函数签名。
答案 3 :(得分:1)
我不喜欢第一种情况 - 父对象只是通过传入进行神奇修改 - 你必须阅读代码或文档才能意识到这种情况正在发生。只传入父级只意味着孩子知道父级 - 而不是孩子也被添加到父级的内部列表中。
第二个例子更好。您还可以从“添加”操作返回子项以允许操作链接,如:
Node2 child = parent.add(new Node2());
答案 4 :(得分:1)
为了方便起见,我认为没有理由不将这两种方法结合起来:
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()应该在子项已经设置父项时抛出异常,或者从父项的子列表中正确删除它。
答案 5 :(得分:0)
如果从TreeNode类派生Node,那么您将自动获得第二个实现。您可以将“自定义”treenode添加到常规Treeview类中。
答案 6 :(得分:0)
首先,您的第一个示例中的错误是: if(parent!= null){ 需要进行此检查,因为您应该有机会创建树的根,但是双状态参数看起来很丑。
首先,您的样本不好,因为执行隐式操作(将子项添加到传递的父项)。
答案 7 :(得分:0)
只有当父节点具有子节点绝对必要时,我才更喜欢实现#1。在这种情况下,客户端代码很可能省略对Node1.add(Node1子节点)的调用,导致稍后出现错误。
我更喜欢实现#2,否则因为使用
这样的用法更清楚Node1 parent = new Node1();
Node1 child = new Node1();
parent.add(child);