ОО Дизайн Вопрос - Родитель / Ребенок (рен) - Круговой? - PullRequest
15 голосов
/ 22 июня 2009

Я довольно новичок в процессе проектирования ОО, поэтому, пожалуйста, потерпите меня ...

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

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

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

Являюсь ли я:

  • На правильном пути?
  • Полностью с базы? Если так, что я должен делать по-другому?

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

Редактировать после 8 ответов:

Спасибо всем. Трудно было выбрать хотя бы один ответ.

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

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

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

Ответы [ 8 ]

11 голосов
/ 22 июня 2009

Циркулярные ссылки хороши и абсолютно стандартны при создании древовидной структуры. Например, объектная модель документа (DOM) HTML имеет родительские и дочерние свойства для каждого узла в дереве DOM:

interface Node {
    // ...
    readonly attribute Node     parentNode;
    readonly attribute NodeList childNodes;
    // ...
}
8 голосов
/ 22 июня 2009

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

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

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

2 голосов
/ 22 июня 2009

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

2 голосов
/ 22 июня 2009

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

2 голосов
/ 22 июня 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 делали для любых гнусных целей.

1 голос
/ 22 июня 2009

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

1 голос
/ 22 июня 2009

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

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

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

0 голосов
/ 22 июня 2009

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

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

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

EDIT

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

...