Как правильно моделировать отношения сущностей дискуссионного форума в ООП? - PullRequest
0 голосов
/ 17 июня 2019

Я напрягаю мускулы ООП и пытаюсь создать веб-приложение для дискуссионного форума MVC. Я работаю над моделированием отношений между сущностями между Forum объектами, Thread объектами и Post объектами. К сожалению, я столкнулся с проблемой, которая поставила мой мозг в штопор. Вот немного предыстории:

Определения:

  • Forum: коллекция обсуждений (например, «Вопросы и ответы»)
  • Thread: коллекция сообщений по определенной теме (например, «В чем смысл жизни, вселенной и всего остального?»)
  • Post: содержит текст сообщения. (например, "Да ... это 42")

Модель:

Вот мой первоначальный черновик для моделирования моих сущностей. В этой модели форумы являются рутом. Форумы могут содержать ноль или более тем, а темы могут содержать 1 или более сообщений. Ради этого вопроса я сохранил все как можно проще.

Forum entity class diagram

Вот мои классы обслуживания: Simplified service classes

Вот как выглядит схема базы данных:

Database schema

Для создания своих объектов я использую мою интерпретацию Pattern Mapper Pattern для преобразования данных из базы данных в объекты сущностей. Многоуровневая архитектура выглядит так: layered architecture

Здесь все становится немного сложнее: Мое понимание хорошего дизайна ООП состоит в том, что сущности не должны иметь дело с такими вещами, как «внешние ключи», потому что это проблемы сохранения данных. Вместо этого сущности должны ссылаться на фактический объект, который представляет «внешний ключ».

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

// get the primary key from the parent object and return it
function getThreadId() {
    return thread.getThreadId();
}

Одна из проблем, с которыми я столкнулся, заключается в определении , когда я должен внедрить ссылки на родительские объекты в сущности.

Подход 1: Мои инстинкты говорят мне, что слой Data Mapper должен отвечать за это поведение. Вот упрощенная версия того, как метод build() может выглядеть в Post преобразователе данных:

// build a post entity
function build( required postId ) {

    // go out to the database and get our dto
    var dto = dao.getById( postId );

    // initialize the entity
    var post = new post( dto.postId, dto.body );

    // inject a reference to the parent object (thread)
    post.setThread( threadDataMapper.getById( dto.threadId ) );

    return post;
}

Я вижу несколько проблем с этим подходом:

  • Я читал, что в ООП дочерние объекты не должны знать о своих родителях и что родители должны отвечать за введение мягких ссылок на своих детей, а не наоборот.

  • Приведенный выше подход кажется неэффективным, поскольку каждая сущность должна выходить и получать копию своего родителя в каждом экземпляре new (). Если у меня есть контроллер, который получает объект Thread, преобразователь данных должен создать экземпляр как нового Thread, так и Forum (2 поездки в базу данных). Если затем мне нужно получить Post из этого Thread через getPostById(), я должен скопировать Post, а затем повторно скопировать Thread и Forum еще раз (3 поездки в базу данных) , Это просто пахнет ужасно для меня.

Подход 2: У меня была еще одна идея - сделать так, чтобы мои родительские сущности сами вводили в своих соответствующих детей. Так, например, Thread может сделать это при получении Post:

// Get a post by id
function getPostById( id ) {

    // get the post entity from the service layer
    var post = postService.getById( arguments.id );

    // inject a reference of this thread into the post
    post.setThread( this );

    return post;

}

Это немного лучше! Тем не менее, основное предостережение, с которым я столкнулся, - это если вы хотите получить прямой доступ к Post в приложении. Допустим, например, что вы хотите иметь страницу для редактирования Post. Поскольку единственный способ правильно построить пост - это пройти через Thread (а единственный способ построить Thread - через Forum), я должен заставить свой контроллер выполнять гораздо больше работы, просто чтобы получить экземпляр конкретного Post. Это похоже на сложность, просто чтобы я мог получить доступ к одной сущности, чтобы я мог ее редактировать.

Подход 3: Наконец, возможно, самый простой подход состоял бы в том, чтобы Forum сущности, Thread сущности и Post сущности были полностью разделены и включали свои внешние ключи в качестве свойств объекта. Тем не менее, этот подход выглядит так, будто я просто использую сущности в качестве причудливых DTO, поскольку они просто хранят данные и не содержат никакой бизнес-логики:

Simple model

Подход 4: ???

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

1 Ответ

0 голосов
/ 21 июня 2019

Я не гуру дизайна ООП, но я думаю, что ответ во многом зависит от логики вашего приложения.

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

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

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

Какой бы вариант вы ни выбрали, он может работать некоторое время, пока сообщение не начнет зависеть от слишком большого количества классов (Тема, Автор, Список лучших сообщений).).Для сохранения собственной согласованности пост должен иметь ссылку на все те классы, которые предоставляют много внешней информации.Это время, когда мы должны закрыть пост для модификации.Все правила публикации, которые зависят от публикации внешних объектов, должны приниматься в качестве зависимости при инициализации.

...