OO Дизайн Циркуляр вопросов для родителей / детей?

Я новичок в процессе объектно-ориентированного проектирования, так что, пожалуйста, потерпите меня ....

У меня есть две сущности, которые мне нужно смоделировать как классы, назовите их Родительский и Дочерний (это достаточно близко к реальной проблемной области). У одного родителя будет один или несколько детей - в этом приложении меня не интересуют бездетные родители.

Мой мозг собирается обедать из-за того, что мне нужно найти что-то одно от другого. В моей базе данных я могу реализовать это с помощью обычных отношений внешнего ключа, а основанная на наборах природа SQL позволяет легко найти всех дочерних элементов для данного родителя или родителя для данного дочернего элемента. А как объекты ...?

Я думаю, что Родитель должен нести коллекцию (список, что угодно) Детей. Я также считаю, что каждый Ребенок должен иметь ссылку на своего Родителя. Однако круговой характер упоминаний вызывает у меня головную боль.

Am I:

  • На правильном пути?
  • Совершенно не на базе? Если да, что мне делать иначе?

Это почти наверняка будет реализовано в VB.NET, но я пока не умею сокращать код.

Изменить после 8 ответов:

Спасибо всем. Было трудно выбрать только один ответ, чтобы принять его.

Чтобы прояснить пару вещей, которые были поставлены под вопрос в ответах:

  • Родитель и Дочерний объект - очень разные сущности - отношения наследования нет вообще. Я выбрал имена, которые сделал, потому что они действительно очень близки к реальной проблемной области, и теперь вижу, что это источник путаницы с точки зрения объектно-ориентированного подхода.
  • Иерархия только на один уровень - у детей никогда не будет детей внутри приложения.

Еще раз спасибо.


person RolandTumble    schedule 22.06.2009    source источник
comment
Могут ли дети иметь детей, или это одноуровневая иерархия? Если он многоуровневый, то вам нужно посмотреть на шаблон Composite.   -  person Harper Shelby    schedule 22.06.2009
comment
Разве это не вопрос времени и пространства с хранением ссылок в узлах? Зависит от ограничений ... если пространство не является проблемой, хранение ссылок в порядке, если они имеют целостность   -  person Aiden Bell    schedule 22.06.2009
comment
@Harper Shelby - Он одноуровневый. У детей никогда не будет собственных детей (в этом приложении). Хотя хороший вопрос.   -  person RolandTumble    schedule 23.06.2009


Ответы (8)


Циклические ссылки прекрасны и абсолютно стандартны при создании древовидной структуры. HTML-модель Document Object Model (DOM), например, имеет родительские и дочерние свойства на каждом node в дереве DOM:

interface Node {
    // ...
    readonly attribute Node     parentNode;
    readonly attribute NodeList childNodes;
    // ...
}
person John Kugelman    schedule 22.06.2009
comment
+1 ... Хороший пример, если циклическое определение не имеет значения на некоторых языках (... попробуйте это на C: P ...) из-за автоматического выделения - person Aiden Bell; 22.06.2009
comment
Это не круговая ссылка. - person Randolpho; 22.06.2009
comment
@Randolpho - нет, это круговое определение - person Aiden Bell; 22.06.2009
comment
Да, этот термин используется здесь некоторыми людьми неправильно и только усугубляет путаницу. - person Spencer Ruport; 22.06.2009
comment
@ Эйден Белл: Может, нам стоит называть это ссылкой на себя? - person Randolpho; 23.06.2009
comment
@Randolpho - зависит от семантики ... когда компилятор его читает ... это циклическое определение ... которое применяется только к методам разрешения и тому подобному, а также к выделению места, когда требования неизвестны. Для экземпляра класса x с членом x.y- ›x, который является ссылкой на себя. Если x.y.z- ›x, тогда у нас есть круговая ссылка, если алгоритм будет проходить по иерархии объектов как таковой. - person Aiden Bell; 23.06.2009

Похоже, ты на правильном пути для меня. Согласно вашей модели предметной области, у родителей есть дети, а у детей есть родители. Возможно, вам потребуется ссылаться друг на друга.

В круговых ссылках нет ничего плохого, просто нужно быть осторожным с тем, что с ними делать. Проблемы могут возникнуть при управлении вашими объектами на стороне сервера в автоматическом режиме, когда вы загружаете их из базы данных. Например, вы получаете объект Child из базы данных с помощью запроса. Вы включаете информацию о родителях? Вы включаете детей родителей?

Инструменты ORM, такие как Lightspeed или Microsoft Entity Framework, обычно справляются с этим с помощью директив «ленивой загрузки». Сначала они получат то, что вам нужно (поэтому, когда вы выбираете Child, он просто получает свойства Child и идентификатор родителя). Если позже вы разыменуете родительский объект, он получит свойства Parent и создаст экземпляр родительского объекта. Если позже вы получите доступ к его коллекции Children, она затем перейдет и извлечет соответствующую дочернюю информацию и создаст дочерние объекты для этой коллекции. Пока они вам не понадобятся, он не заполняет его.

person womp    schedule 22.06.2009

Я считаю разумным иметь возможность перемещаться по графу объектов таким образом. Трудно понять, есть ли у вас для этого уважительная причина из вашего сообщения, но я не думаю, что ссылки сами по себе доказывают плохой дизайн.

person Robert    schedule 22.06.2009

Я верю, что вы на правильном пути. Почему у вас болит голова от кругового характера ссылок? В чем заключается основная проблема, с которой Parent ссылается на своих дочерних элементов, а Child имеет ссылку на своего родителя?

person Paul Sonier    schedule 22.06.2009
comment
Я думаю, это просто тренировка всех этих лет нормализованных структур таблиц ... - person RolandTumble; 23.06.2009
comment
Ах да, я понимаю. Имейте в виду, что в мире SQL есть дополнительный источник данных; сама база данных, содержащая таблицы, к которым можно запрашивать; на уровне базы данных есть прямая ссылка на родительский элемент, который там используется; в структуре вашего класса нет такой запрашиваемой ссылки, по которой можно было бы искать родителей. В объектном дизайне нормализация может быть ошибкой из-за невозможности запроса данных; ссылки должны быть явными. - person Paul Sonier; 23.06.2009

Вы говорите об иерархии классов, где родительский класс знает о своих дочерних классах?

Вам следует избегать этого любой ценой.

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

Тем не менее, мне кажется, что вы пытаетесь создать не иерархию классов, а иерархию коллекций, то есть дерево. В таком случае да, вы на правильном пути; это обычная парадигма. Родительский узел имеет набор дочерних узлов, а дочерний узел имеет ссылку на родительский узел.

Дело в том? Они одного класса! Вот очень простой пример на C #:

public class Node
{
  public readonly Node Parent; // null Parent indicates root node
  public readonly List<Node> Children = new List<Node>();
  public Node(Node parent)
  {
     Parent = parent;
  }
  public Node()
  {
     parent = null;
  }
  public void AddChild(Node node)
  {
     Children.Add(node);
  }
}

Я чувствую, что это то, что тебе действительно нужно. Используя эту парадигму, вы затем подклассифицируете Node для любых гнусных целей, которые у вас могут быть.

person Randolpho    schedule 22.06.2009
comment
Мне это показалось скорее ограничением, чем отношениями наследования. - person Robert; 22.06.2009
comment
@Robert: Я согласен, но вопросник был не очень ясен, поэтому я попросил разъяснений, а затем отредактировал. - person Randolpho; 22.06.2009
comment
Классы будут отличаться друг от друга. Дети (очень) не то же самое, что родители. Но я вижу, в чем сначала мне было не так ясно. - person RolandTumble; 23.06.2009
comment
@RolandTumble: Это нормально. Парадигма также работает для гетерогенных ситуаций. Проблема, о которой я беспокоюсь и которую я рекомендую вам избегать любой ценой, - это случай, когда Child является производным от Parent, а не является дочерним узлом Parent. - person Randolpho; 23.06.2009

Если я понимаю, что объекты P содержат массив объектов P-> c [], представляющих детей. И любой узел P без дочерних элементов является листом ... с каждым P, содержащим P-> P '(родительский).

Указанное вами решение с родительскими элементами, содержащими ссылки на дочерние элементы, и наоборот, устраняет необходимость перемещаться по дереву для получения предков данного дочернего элемента и дочерних элементов узла. На самом деле это просто дерево, по которому вы можете создавать всевозможные ссылки и алгоритмы для его обхода и перечисления. Что нормально!

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

person Aiden Bell    schedule 22.06.2009

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

person Spencer Ruport    schedule 22.06.2009

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

Вероятно, вам следует еще раз изучить, почему вашим детям нужна обратная ссылка на родителя и наоборот. Я склоняюсь к тому, чтобы у родителей была группа детей. Затем вы можете добавить функциональность к родительскому объекту, чтобы проверить, является ли дочерний объект дочерним по отношению к экземпляру.

Лучшее объяснение цели также может быть немного более полезным ...

ИЗМЕНИТЬ

Я прочитал еще немного (и выслушал комментарии) ... и оказалось, что я совершенно не прав. Циркулярные ссылки действительно имеют свое место, если вы осторожны с ними и не позволяете им выйти из-под контроля.

person Justin Niessner    schedule 22.06.2009
comment
В вашей архитектуре никогда не должно быть циклических ссылок. Почему нет? Законно любопытно. - person Chris McCall; 22.06.2009
comment
Теоретически такая циклическая ссылка может привести к бесконечно повторяющемуся коду. Скажем, у вас есть код, который загружает вашего родителя, затем загружает потомков, который снова загружает родительский элемент, который снова загружает дочерний элемент, и дальше ... и дальше ... - person Justin Niessner; 22.06.2009
comment
Инструменты ORM часто по умолчанию генерируют циклические ссылки для ассоциаций. Не обязательно указывает на недостаток дизайна. - person womp; 22.06.2009
comment
@Justin, с каких пор это могло быть использовано ненадлежащим образом, стало хорошей причиной не реализовывать дизайн? - person Spencer Ruport; 22.06.2009
comment
Хорошая точка зрения. Прочтите еще пару статей после того, как я дал свой ответ. Я упустил пару веских причин иметь циркулярные ссылки. ... пора воздержаться от ТАК, когда сильно устаешь. - person Justin Niessner; 22.06.2009
comment
Мне кажется, что люди, преувеличивающие, что вы неправильно понимаете как ваш пост, так и вопрос. - person Randolpho; 22.06.2009