Два других ответа - одно направление (+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