2009-03-10 13 views
7

Je travaille avec du code qui ajoute un nœud enfant à son parent dans le constructeur de l'enfant. Le code ressemble à ceci:Meilleure pratique: Ajouter un noeud enfant à un parent dans le constructeur enfant ou non?

Classe:

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); 
    } 
} 

Utilisation:

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

En mettant en œuvre cette façon l'utilisateur de la classe Node1 ne pas ajouter explicitement le nœud enfant (moins de code) à son parent et vous avez garanti qu'un noeud enfant a un parent.

Personnellement, je ne l'aurais pas écrit comme ça, mais plus comme ce qui suit:

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); 

Ma question est, est-ce une bonne idée de mettre en œuvre comme indiqué dans la classe Node1 ou sont ANY objections de le faire de cette façon? Ou n'y a-t-il aucun argument pour expliquer pourquoi l'un est meilleur que l'autre?

Répondre

11

Personnellement, je n'aime pas le premier exemple parce que vous ajoutez un nœud qui n'est pas encore "prêt" (car le constructeur n'a pas fini d'exécuter). Dans la plupart des cas, cela fonctionnera bien, mais dans les cas extrêmes, vous pouvez avoir des bugs qui sont assez difficiles à trouver.

+0

+1: plus ou moins ce que je l'aurais dit. –

+0

C'est un bon point, il vaut mieux ne pas l'utiliser dans un constructeur. –

1

Je pense que les deux implémentations sont correctes.

La question est de savoir comment vous allez utiliser cette classe: créerez-vous d'abord une liste de nœuds, puis vous commencerez à ajouter leurs relations ou allez-vous le faire de façon ordonnée, comme dans votre exemple?

La deuxième solution offre plus de flexibilité, même si vous voulez utiliser Node1 comme superclasse, vous n'êtes pas lié à la signature du constructeur.

2

Je voudrais utiliser le second cas car alors je serai en mesure d'ajouter des enfants plus tard, mais pas seulement dans le constructeur.

0

Si vous dérivez un nœud de la classe TreeNode, vous obtenez automatiquement votre 2ème implémentation. Vous pouvez ajouter votre treenode "personnalisé" à la classe Treeview classique.

1

Je n'aime pas le premier cas - l'objet parent est magiquement modifié juste en étant transmis - vous devez lire du code ou des docs pour réaliser que cela se passe. Le simple passage dans le parent implique seulement que l'enfant connaît le parent - pas que l'enfant soit également ajouté à la liste interne du parent.

Le deuxième exemple est meilleur. Vous pouvez également retourner l'enfant de l'opération « ajouter » pour permettre un fonctionnement enchaînant comme:

Node2 child = parent.add(new Node2()); 
1

Je ne vois aucune raison pourquoi ne pas combiner les deux approches pour des raisons pratiques:

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); 
    } 
} 

Notez que setParent () devrait soit lancer une exception quand l'enfant a déjà son parent, soit se retirer correctement de la liste des enfants de l'ancien parent.

0

Tout d'abord le mauvais dans votre premier échantillon est la suivante: si (parent! = Null) { cette vérification est nécessaire parce que vous devriez avoir une chance de créer la racine d'un arbre, mais le paramètre à deux états semble laid.

Également d'abord votre échantillon n'est pas bon parce que vous faites des actions implicites (en ajoutant l'enfant au parent passé).

0

Je préférerais l'implémentation n ° 1 uniquement lorsqu'il est absolument essentiel d'avoir un nœud parent avec un nœud enfant. Dans ce cas, il est tout à fait possible que le code client omette l'appel à Node1.add (enfant Node1), ce qui entraîne des erreurs plus tard.

Je préfère la mise en œuvre # 2 sinon parce qu'il est plus clair d'avoir une utilisation comme

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