как моделировать отношения объектов ценности?

контекст:
У меня есть объект Книга. Книга может иметь одно или несколько описаний. Описания являются объектами-значениями.

проблема:
Описание может быть более конкретным, чем другое описание. Например, если описание содержит содержание книги и то, как выглядит обложка, оно является более конкретным, чем описание, в котором обсуждается только то, как выглядит обложка. Я не знаю, как это смоделировать и как сохранить в репозитории. Ни книга, ни описание книги не обязаны знать эти отношения. Какой-то другой объект может обработать это, а затем попросить репозиторий сохранить отношения. Но BookRepository.addMoreSpecificDescription(Description, MoreSpecificDescription) кажется сложным для сохранения репозитория.

Как такие вещи обрабатываются в DDD?


person koen    schedule 18.12.2009    source источник


Ответы (3)


Два других ответа - одно направление (+1 кстати). Я вхожу после того, как вы отредактировали исходный вопрос, так что вот мои два цента...

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

Чтобы использовать ваш пример, вы определяете «Описание» как объект значения. Это говорит мне о том, что «Описание» с несколькими свойствами может использоваться несколькими книгами. В реальном мире это не имеет смысла, поскольку все мы знаем, что каждая книга имеет уникальные описания, написанные автором или издателем книги. Хе-хе. Итак, я бы сказал, что описания на самом деле не являются объектами-значениями, а сами являются дополнительными объектами Entity в границах вашей агрегированной корневой сущности книги (у вас может быть несколько сущностей в пределах одной совокупной корневой сущности). Даже переизданные книги, более новая редакция и т. д. имеют немного другие описания, описывающие это небольшое изменение.

Я полагаю, что это отвечает на ваш вопрос - создайте объекты сущностей описаний и защитите их за своим основным сводным корнем объекта книги (например, Book.GetDescriptions()...). Остальная часть этого ответа посвящена тому, как я обрабатываю объекты значений в репозиториях, для других, читающих этот пост...

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

При проектировании, ориентированном на домен, вы моделируете объекты-значения в своем домене, а не в хранилище данных. Это ключевая фраза. Это означает, что вы не проектируете объекты-значения для хранения в качестве независимых объектов в хранилище данных, вы можете хранить их как хотите!

Возьмем обычный пример DDD для объектов-значений, которым является Address(). DDD представляет, что почтовый адрес является идеальным примером объекта-ценности, поскольку определение объекта-ценности — это объект, чьи свойства суммируются для создания уникальности объекта. Если свойство изменится, это будет другой объект-значение. И один и тот же Объект-Ценность (сумма его свойств) может использоваться совместно с другими Сущностями.

Почтовый адрес — это местоположение, долгота/широта определенного места на планете. Несколько человек могут жить по этому адресу, и когда кто-то переезжает, новые люди, занимающие тот же почтовый адрес, теперь используют один и тот же объект-значение.

Итак, у меня есть объект Person() с объектом MailingAddress(), в котором содержится адресная информация. Он защищен корнем агрегата Person() с помощью методов/сервисов get/update/create.

Теперь, как нам хранить это и делиться им с людьми в одном доме? А, в этом и заключается DDD — вы не моделируете свое хранилище данных прямо из своего DDD (хотя это было бы неплохо). С учетом сказанного вы просто создаете одну таблицу, которая представляет ваш объект Person, и в ней есть столбцы для вашего почтового адреса. Задача вашего репозитория состоит в том, чтобы вернуть эту информацию обратно в ваш объект Person() и MailingAddress() из хранилища данных и разделить ее во время операций создания/обновления.

Да, теперь у вас будут дубликаты данных в вашем хранилище данных. Три сущности Person() с одним и тем же почтовым адресом теперь имеют три отдельные копии этих данных Value Object — и это нормально! Ценные объекты предназначены для того, чтобы их можно было легко скопировать и уничтожить. «Копировать» — оптимальное слово в пьесе DDD.

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

Все вышеперечисленное является strict-DDD. Но DDD предназначен для того, чтобы быть просто «предложениями», а не правилами, по которым нужно жить. Вот почему вы можете делать то, что делал я и многие другие, в стиле свободного DDD. Если вам не нравятся скопированные данные, ваш единственный вариант заключается в том, что вы можете создать отдельную таблицу для MailingAddress() и прикрепить к ней столбец Identity, а также обновить свой объект MailingAddress(), чтобы теперь иметь на нем эту идентификацию - зная, что вы используете это удостоверение только для того, чтобы связать его с другими объектами Person(), которые его разделяют (лично мне нравится третья таблица отношений «многие ко многим», чтобы поддерживать скорость запросов). Вы должны замаскировать эту Идентификацию (т. е. внутренний модификатор) от раскрытия за пределами вашего Совокупного корня/домена, чтобы другие уровни (такие как Приложение или пользовательский интерфейс) не знали о столбце Идентификация MailingAddress, если это возможно. Кроме того, я бы создал специальный репозиторий только для MailingAddress и использовал ваш слой PersonService, чтобы объединить их в правильный объект Person.MailingAddress().

Извините за назойливость... :)

person eduncan911    schedule 22.12.2009

Во-первых, я считаю, что обзоры должны быть сущностями.

Во-вторых, почему вы пытаетесь моделировать отношения между отзывами? Я не вижу между ними естественной связи. «Более конкретно, чем» слишком расплывчато, чтобы быть полезным в качестве отношения.

Если у вас возникают трудности с моделированием ситуации, это говорит о том, что, возможно, отношений нет.

person jason    schedule 18.12.2009
comment
Примечание. Я обновил пример, используя описание вместо обзора. Отношения неестественные, я думаю. Допустим, пользователю нравится видеть описания, которые показывают сводку. Тогда подойдет любое описание, показывающее краткое изложение (и многое другое). Вот что я имею в виду под «более конкретным, чем». - person koen; 19.12.2009

Я согласен с Джейсоном. Я не знаю, каково ваше обоснование того, что обзоры оценивают объекты.

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

person Nathan Hughes    schedule 18.12.2009
comment
Причина в том, что они неизменны. Рецензия на книгу выбрана неудачно. Описание книги лучше подошло бы для примера. Описание книги — это метаданные, идентичность которых меня не волнует. Я обновлю пример. - person koen; 19.12.2009