2009-07-13 3 views
1

Ich finde es schwierig, ein anständiges Beispiel zu finden, wie eine Eltern-Kind-Hierarchie-Klasse implementiert werden kann. Ich habe ein TreeView-Steuerelement, das ich in eine Klassenhierarchie konvertieren möchte, indem ich jedem Knoten zusätzliche Daten hinzufüge und in der Lage bin, mit IEnumerable problemlos über die Knoten jedes Elternteils zu iterieren.Implementieren Sie eine Eltern-Kind-Klassenhierarchie

public IEnumerable<Node> GetAllChildsFromParent(Node parent) 
{ 
    foreach (Node node in parent.NodeChildsCollection) 
    { 
     yield return node; 
    } 
} 

Ich habe bereits das folgende Stück Code implementiert, jedoch blieb stecken und nicht wirklich eine Ahnung, ob ich auf dem richtigen Weg bin oder nicht? Wie soll ich fortfahren, um das zu vervollständigen?

public class NodeChildsCollection : IEnumerable<Node> 
{ 
    IList<Node> nodeCollection = new List<Node>(); 
    Node parent; 

    public Node Parent 
    { 
     get { return parent; } 
     set { parent = value; } 
    } 

    public NodeChildsCollection() 
    { 
    } 


    public void AddNode(Node parent, Node child) 
    { 
     this.parent = parent; 
     nodeCollection.Add(child); 
    } 

    #region IEnumerable<Node> Members 

    public IEnumerator<Node> GetEnumerator() 
    { 
     foreach (Node node in nodeCollection) 
     { 
      yield return node; 
     } 
    } 

    #endregion 

    #region IEnumerable Members 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 
} 

public class Node 
{ 

    NodeChildsCollection nodeChildsCollection = new NodeChildsCollection(); 

    public Node Parent 
    { 
     get { return nodeChildsCollection.Parent; } 
     set { nodeChildsCollection.Parent = value; } 
    } 


    public void AddChild(Node child) 
    { 
     nodeChildsCollection.AddNode(this, child); 
    } 
} 

Antwort

2

Sie mischen die Verantwortung der Knoten mit den Aufgaben der Sammlung. Sehen Sie, wie Sie das übergeordnete Element in der Sammlung festlegen. Es ist nicht die Sammlung, die ein Elternteil hat; es ist der Knoten.

würde ich meine Knoten strukturieren wie so:

public class Node 
{ 
    public Node Parent {get;set;} // null for roots 

    public NodeCollection Children {get; private set;} 

    public Node() 
    { 
    Children = new NodeCollection(); 
    Children.ChildAdded += ChildAdded; 
    Children.ChildRemoved += ChildRemoved; 
    }; 
    private void ChildAdded(object sender, NodeEvent args) 
    { 
    if(args.Child.Parent != null) 
     throw new ParentNotDeadYetAdoptionException("Child already has parent"); 
    args.Child.Parent = this; 
    } 
    private void ChildRemoved(object sender, NodeEvent args) 
    { 
    args.Child.Parent = null; 
    } 
} 

Und die NodeCollection würde aussehen wie

public class NodeCollection : INodeCollection {/*...*/} 

und INodeCollection wäre:

public interface INodeColleciton : IList<Node> 
{ 
    event EventHandler<NodeEvent> ChildAdded; 
    event EventHandler<NodeEvent> ChildRemoved; 
} 

Die Sammlung Verantwortlichkeiten auf sind die Child-Auflistungseigenschaft des Knotens. Sie können natürlich Knoten INodeCollection implementieren, aber das ist eine Frage der Programmierung Geschmack. Ich bevorzuge das öffentliche Eigentum der Kinder (sein, wie der Rahmen entworfen wird).

Mit dieser Implementierung müssen Sie keine "GetChildren" -Methode implementieren; Das öffentliche Kinderhaus stellt sie allen zur Verfügung.

1

Wenn Sie den Begriff einer baumartigen Datenstruktur aus den spezifischen Daten werden gespeichert trennen wollen, machen es zu einem Mehrzweckbehälter durch Generika machen.

Wenn der Baum einen einzelnen Stamm hat, ist ein Baumbestand selbst eine Sammlung von Baumkronen. Daher sollte (wie bei jeder Sammlung) die Methode zum Hinzufügen eines Artikels Add heißen. Die untergeordnete Sammlung zu einem separaten Objekt zu machen, würde nur Sinn ergeben, wenn Sie häufig Sammlungen von Bäumen haben. Dies tritt in TreeViews in der Windows-Benutzeroberfläche auf, da das Stammverzeichnis eines TreeView-Objekts mehrere Knoten enthält und nicht nur ein einzelner Stammzielknoten. Doch in so etwas wie die XML oder HTML-DOM, gibt es immer eine einzige Wurzel, und so denke ich, etwas einfacher geeignet ist.

Schließlich müssen Sie nicht die IEnumerable Zeug mit yield return implementieren - nur auf eine Standard-Container-Implementierung weiterleiten.

public class TreeNode<TValue> : IEnumerable<TreeNode<TValue>> 
{ 
    private List<TreeNode<TValue>> _children = new List<TreeNode<TValue>>(); 

    public TreeNode<TValue> Parent { get; private set; } 

    public void Add(TreeNode<TValue> child) 
    { 
     _children.Add(child); 
     child.Parent = this; 
    } 

    public void Remove(TreeNode<TValue> child) 
    { 
     _children.Remove(child); 
     child.Parent = null; 
    } 

    public IEnumerator<TreeNode<TValue>> GetEnumerator() 
    { 
     return _children.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return _children.GetEnumerator(); 
    }  
} 

In der Tat könnte man es IList<TreeNode<TValue>> machen implementieren und alle Methoden vorwärts auf die Liste mit geeigneter Manipulation der Parent Eigenschaft, wenn Hinzufügen/Entfernen von Kindern.