Практично кожен проект, який має якусь редаговану модель або документ, матиме ієрархічну структуру до нього. Це може стати в нагоді реалізувати "ієрархічний вузол" як базовий клас для різних об'єктів. Часто пов'язаний список (рідний брат, друга модель) є природним способом росту багатьох бібліотек класів, проте діти можуть бути різного типу, і, ймовірно, " об'єктна модель " - це не те, що ми розглядаємо, коли говоримо про дерева взагалі.
Моя улюблена реалізація дерева (вузла) вашої першої моделі - це однолінійний (в C #):
public class node : List<node> { /* props go here */ }
Спадковуйте із загального списку вашого власного типу (або успадковуйте від будь-якого іншого загального колекціонування власного типу). Ходити можливо в одному напрямку: сформуйте корінь вниз (предмети не знають своїх батьків).
Дерево лише для батьків
Ще одна модель, яку ви не згадали, - це та, де кожна дитина має посилання на свого батька:
null
|
+---------+---------------------------------+
| parent |
| root |
+-------------------------------------------+
| | |
+---------+------+ +-------+--------+ +--+-------------+
| parent | | parent | | parent |
| node 1 | | node 2 | | node 3 |
+----------------+ +----------------+ +----------------+
Ходити по цьому дереву можливо лише навпаки, зазвичай всі ці вузли зберігатимуться в колекції (масив, хештел, словник тощо), і вузол буде розташований шляхом пошуку колекції за іншими критеріями, ніж ієрархічне положення в дерево, яке, як правило, не має первинного значення.
Ці дерева лише для батьків є звичайними програмами баз даних. Досить легко знайти дітей вузла з виразами "SELECT * WHERE ParentId = x". Однак ми рідко зустрічаємо ці перетворені в об'єкти класу дерева дерева як такі. У державних (настільних) додатках вони можуть бути зафіксовані в існуючі елементи управління деревом. У веб-програмах без громадянства навіть це може бути малоймовірним. Я бачив ORM-картографічні інструменти-генератори класів, які викидають помилки переповнення стека під час генерації класів для таблиць, які мають відношення до себе (хихикання), тому, можливо, ці дерева не є такими поширеними.
двонаправлені судноплавні дерева
Однак у більшості практичних випадків зручно мати найкращі з обох світів. Вузли, у яких є список дітей і крім того, знають свого батька: двонаправлені навігаційні дерева.
null
|
+--------------------+--------------------+
| parent |
| root |
| child1 child2 child3 |
+--+------------------+----------------+--+
| | |
+---------+-----+ +-------+-------+ +---+-----------+
| parent | | parent | | parent |
| node1 | | node2 | | node3 |
| child1 child2 | | child1 child2 | | child1 child2 |
+--+---------+--+ +--+---------+--+ +--+---------+--+
| | | | | |
Це враховує ще багато аспектів, які слід враховувати:
- Де здійснити зв'язування та від’єднання батьків?
- нехай дбає про логіку ділової активності, а аспект залиште поза вузла (вони забудуть!)
- у вузлах є методи створення дітей (не дозволяє повторно замовляти) (вибір Microsofts в їх реалізації System.Xml.XmlDocument DOM, який майже звів мене з розуму, коли я вперше зіткнувся з цим)
- Вузли приймають батьків у своєму конструкторі (не дозволяє повторно замовляти)
- у всіх методах додати (), вставити () та видалити () та їх перевантаження вузлів (зазвичай мій вибір)
- Наполегливість
- Як ходити по дереву при збереженні (залиште, наприклад, батьківські посилання)
- Як відновити двостороння зв'язок після десеріалізації (встановлення всіх батьків знову як постдесеріалізаційна дія)
- Сповіщення
- Статичні механізми (прапор IsDirty), обробляють рекурсивно властивості?
- Події, підказки через батьків, вниз через дітей або обома способами (розглянемо, наприклад, насос для повідомлень Windows).
Тепер, щоб відповісти на питання , двоспрямовані судноплавні дерева, як правило, (в моїй кар’єрі та на сьогоднішній день) є найбільш широко використовуваними. Прикладами є реалізація Microsofts системи System.Windows.Forms.Control або System.Web.UI.Control у рамках .Net, а також кожна реалізація DOM (Document Object Model) матиме вузли, які знають свого батьківського, а також перерахування своїх дітей. Причина: простота використання над простотою реалізації. Крім того, це зазвичай базові класи для більш конкретних класів (XmlNode може бути базою класів тегів, атрибутів і тексту), і ці базові класи є природними місцями для розміщення загальної архітектури серіалізації та обробки подій.
Дерево лежить в основі багатьох архітектур, і мати можливість вільно орієнтуватися означає швидше реалізовувати рішення.