2009-03-10 2 views
7

Я работаю с некоторым кодом, который добавляет дочерний узел в его родительский элемент в конструкторе child. Код выглядит примерно так:Лучшая практика. Добавление дочернего узла в родительский элемент в дочернем конструкторе или нет?

Класс:

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 или есть какой-либо возражения, чтобы сделать это таким образом? Или нет аргументов, почему один лучше другого?

ответ

11

Мне лично не нравится первый пример, потому что вы добавляете узел, который еще не «готов» (так как конструктор не закончил выполнение). В большинстве случаев он будет работать нормально, но в крайнем случае у вас могут быть ошибки, которые довольно сложно найти.

+0

+1: Довольно много, что я бы сказал. –

+0

Это хороший момент, лучше не использовать это в конструкторе. –

1

Я думаю, что обе реализации в порядке.

Вопрос в том, как вы будете использовать этот класс: сначала вы создадите список узлов, а затем начнете добавлять свои отношения или будете делать это упорядоченным образом, как в вашем примере?

Второе решение обеспечивает большую гибкость, также если вы когда-либо захотите использовать Node1 в качестве суперкласса, вы не привязаны к сигнатуре конструктора.

2

Я бы использовал второй случай, так как позже я смогу добавить детей позже, но не только в конструкторе.

0

Если вы вывели узел из класса TreeNode, вы автоматически получите вторую реализацию своей. Вы можете добавить свой «настраиваемый» treenode в обычный класс Treeview.

1

Мне не нравится первый случай - родительский объект магически модифицирован, просто пройдя его - вы должны прочитать код или документы, чтобы понять, что это происходит. Просто передача родительского объекта подразумевает, что ребенок знает родителя, а не того, что ребенок добавляется во внутренний список родителя.

Второй пример лучше. Вы можете также вернуть ребенка из операции «добавить», чтобы операция цепочки как:

Node2 child = parent.add(new Node2()); 
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 () должен либо генерировать исключение, когда у ребенка уже есть свой родительский набор, либо правильно удалить его из дочернего списка прежнего родителя.

0

Во-первых, плохо в первом образце: если (родитель! = NULL) { нужен этот чек, потому что вы должны иметь возможность создать корень дерева, но два состояния параметра выглядит некрасиво.

Кроме того, сначала ваш образец не хорош, так как выполняет неявные действия (добавление дочернего элемента в родительский элемент).

0

Я предпочел бы реализацию # 1 только тогда, когда совершенно необходимо иметь родительский узел с дочерним узлом. В этом случае вполне возможно, что код клиента опустит вызов Node1.add (Node1 child), что приведет к ошибкам позже.

Я предпочитаю реализации # 2 в противном случае, потому что это понятнее иметь использование как

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