Я напрягаю мускулы ООП и пытаюсь создать веб-приложение для дискуссионного форума MVC. Я работаю над моделированием отношений между сущностями между Forum
объектами, Thread
объектами и Post
объектами. К сожалению, я столкнулся с проблемой, которая поставила мой мозг в штопор. Вот немного предыстории:
Определения:
Forum
: коллекция обсуждений (например, «Вопросы и ответы»)
Thread
: коллекция сообщений по определенной теме (например,
«В чем смысл жизни, вселенной и всего остального?»)
Post
: содержит текст сообщения.
(например, "Да ... это 42")
Модель:
Вот мой первоначальный черновик для моделирования моих сущностей. В этой модели форумы являются рутом. Форумы могут содержать ноль или более тем, а темы могут содержать 1 или более сообщений. Ради этого вопроса я сохранил все как можно проще.
![Forum entity class diagram](https://i.imgur.com/srhXDA8.png)
Вот мои классы обслуживания:
![Simplified service classes](https://i.stack.imgur.com/uGewk.png)
Вот как выглядит схема базы данных:
![Database schema](https://i.stack.imgur.com/PXxhN.png)
Для создания своих объектов я использую мою интерпретацию Pattern Mapper Pattern для преобразования данных из базы данных в объекты сущностей. Многоуровневая архитектура выглядит так: ![layered architecture](https://i.stack.imgur.com/bUvNL.png)
Здесь все становится немного сложнее:
Мое понимание хорошего дизайна ООП состоит в том, что сущности не должны иметь дело с такими вещами, как «внешние ключи», потому что это проблемы сохранения данных. Вместо этого сущности должны ссылаться на фактический объект, который представляет «внешний ключ».
Поэтому я хочу убедиться, что мои дочерние объекты (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](https://i.stack.imgur.com/auULx.png)
Подход 4: ???
Так вот где я сейчас нахожусь. Возможно, я собираюсь решить эту проблему совершенно неправильно, или, может быть, уже существует шаблон для этого типа модели, о котором я не знаю. Буду признателен за любую помощь или понимание, которое вы можете предложить!