Fast jedes Projekt mit einem bearbeitbaren Modell oder Dokument hat eine hierarchische Struktur. Es kann nützlich sein, den 'hierarchischen Knoten' als Basisklasse für verschiedene Entitäten zu implementieren. Oft ist die verknüpfte Liste (Kindergeschwister, 2. Modell) die natürliche Art und Weise, wie viele Klassenbibliotheken wachsen, die Kinder können jedoch von unterschiedlichem Typ sein, und wahrscheinlich ist ein " Objektmodell " nicht das, was wir betrachten, wenn wir über Bäume im Allgemeinen sprechen.
Meine Lieblingsimplementierung eines Baums (Knotens) Ihres ersten Modells ist ein Einzeiler (in C #):
public class node : List<node> { /* props go here */ }
Von einer generischen Liste Ihres eigenen Typs erben (oder von einer anderen generischen Sammlung Ihres eigenen Typs erben). Das Gehen ist in eine Richtung möglich: Bilden Sie die Wurzel nach unten (Gegenstände kennen ihre Eltern nicht).
Eltern nur Baum
Ein anderes Modell, das Sie nicht erwähnt haben, ist das, bei dem jedes Kind einen Verweis auf sein Elternteil hat:
null
|
+---------+---------------------------------+
| parent |
| root |
+-------------------------------------------+
| | |
+---------+------+ +-------+--------+ +--+-------------+
| parent | | parent | | parent |
| node 1 | | node 2 | | node 3 |
+----------------+ +----------------+ +----------------+
Das Gehen in diesem Baum ist nur in umgekehrter Richtung möglich. Normalerweise werden alle diese Knoten in einer Sammlung (Array, Hashtable, Wörterbuch usw.) gespeichert, und ein Knoten wird durch Durchsuchen der Sammlung nach anderen Kriterien als der hierarchischen Position in der Datenbank gefunden Baum, der in der Regel nicht von primärer Bedeutung wäre.
Diese übergeordneten Baumstrukturen werden normalerweise in Datenbankanwendungen angezeigt. Mit den Anweisungen "SELECT * WHERE ParentId = x" können die untergeordneten Elemente eines Knotens ganz einfach gefunden werden. Wir finden diese jedoch selten als solche in Baumknotenklassenobjekte transformiert. In Statefull-Anwendungen (Desktop-Anwendungen) können sie in vorhandene Tree-Node-Steuerelemente eingebunden werden. In zustandslosen (Web-) Anwendungen kann dies sogar unwahrscheinlich sein. Ich habe gesehen, dass ORM-Mapping-Klassengenerator-Tools beim Generieren von Klassen für Tabellen, die eine Beziehung zu sich selbst haben (chuckle), Stapelüberlauffehler auslösen.
bidirektionale schiffbare Bäume
In den meisten praktischen Fällen ist es jedoch praktisch, das Beste aus beiden Welten zu haben. Knoten, die eine Liste von Kindern haben und zusätzlich deren Eltern kennen: bidirektionale navigierbare Bäume.
null
|
+--------------------+--------------------+
| parent |
| root |
| child1 child2 child3 |
+--+------------------+----------------+--+
| | |
+---------+-----+ +-------+-------+ +---+-----------+
| parent | | parent | | parent |
| node1 | | node2 | | node3 |
| child1 child2 | | child1 child2 | | child1 child2 |
+--+---------+--+ +--+---------+--+ +--+---------+--+
| | | | | |
Dies bringt viele weitere Aspekte mit sich, die berücksichtigt werden müssen:
- Wo kann die Verknüpfung und Aufhebung der Verknüpfung von Eltern implementiert werden?
- Lass die Geschäftslogik auf dich aufpassen und lass den Aspekt aus dem Knoten (sie werden es vergessen!)
- Knoten haben Methoden zum Erstellen von Kindern (erlaubt keine Neuordnung) (Microsofts Auswahl in ihrer System.Xml.XmlDocument-DOM-Implementierung, was mich fast verrückt gemacht hat, als ich es zum ersten Mal sah)
- Knoten nehmen ein übergeordnetes Element in ihren Konstruktor auf (keine Neuordnung möglich)
- in allen add (), insert () und remove () Methoden und deren Überladung der Knoten (normalerweise meine Wahl)
- Ausdauer
- Wie man beim Fortbestehen auf dem Baum herumläuft (zum Beispiel Eltern-Links weglassen)
- Neuerstellen der bidirektionalen Verknüpfung nach der Deserialisierung (erneutes Festlegen aller übergeordneten Elemente als Aktion nach der Deserialisierung)
- Benachrichtigungen
- Statische Mechanismen (IsDirty-Flag), die in Eigenschaften rekursiv behandelt werden?
- Ereignisse sprudeln durch die Eltern, durch die Kinder oder in beide Richtungen (z. B. die Windows-Nachrichtenpumpe).
Um die Frage zu beantworten : Bidirektionale schiffbare Bäume sind (in meiner bisherigen Karriere und auf meinem Gebiet) die am häufigsten verwendeten. Beispiele sind Microsofts Implementierung von System.Windows.Forms.Control oder von System.Web.UI.Control im .Net-Framework, aber auch jede DOM-Implementierung (Document Object Model) verfügt über Knoten, deren übergeordnetes Element sowie eine Aufzählung bekannt sind ihrer Kinder. Der Grund: Benutzerfreundlichkeit über einfache Implementierung. Außerdem handelt es sich normalerweise um Basisklassen für spezifischere Klassen (XmlNode kann die Basis der Tag-, Attribut- und Textklassen sein). Diese Basisklassen sind natürliche Orte, um generische Serialisierungs- und Ereignisbehandlungsarchitekturen zu platzieren.
Tree ist das Herzstück vieler Architekturen. Wenn Sie frei navigieren können, können Sie Lösungen schneller implementieren.