Дизайн, управляемый доменом: когда создавать совокупный корень?

Я пытаюсь реализовать DDD в первый раз с проектом ASP.NET MVC, и я борюсь с несколькими вещами.

У меня есть 2 связанных лица, компания и поставщик. Моя первоначальная мысль заключалась в том, что Company — это совокупный корень, а Supplier — объект-значение для Company. Итак, у меня есть репозиторий для компании и нет для поставщика.

Но когда я начал создавать свое приложение, мне потребовались отдельные формы списка, создания и обновления для поставщика. Список был прост, я мог вызвать Company.Suppliers, и создать его было ужасно, я мог сделать Company.Suppliers.Add(supplier), но обновление вызывает у меня головную боль. Поскольку мне нужен только один объект, и я не могу точно вставить его в память между формами, мне пришлось повторно загрузить компанию и всех поставщиков и найти тот, который мне нужен, чтобы связать его и снова изменить его и сохранить. вернуться к бд.

Мне просто нужно было сделать GetOne, если бы у меня был репозиторий для Поставщика. Я мог бы добавить некоторые обходные пути, добавив GetOneSupplier в мою компанию или CompanyRepository, но это кажется мусором.

Итак, мне действительно интересно, действительно ли это объект-значение, а не сама полноценная сущность домена.

TLDR;

Нужен ли отдельный список/создание/обновление представления/страниц признаком того, что объект должен быть собственным корнем?


person Michael Cook    schedule 01.10.2009    source источник


Ответы (2)


Основываясь на вашей терминологии, я предполагаю, что вы выполняете DDD на основе книги Эрика Эванса. Похоже, вы уже определили проблему с вашим первоначальным подходом к моделированию, и вы правы.

Вы упомянули, что думали о поставщике как о Value Object... Я полагаю, что это не так. Value Object — это то, что в первую очередь идентифицируется по своим свойствам. Например, дата «30 сентября 2009 г.» является объектом-значением. Почему? Потому что все экземпляры даты с другой комбинацией месяца/дня/года являются разными датами. Все экземпляры даты с одним и тем же сочетанием месяца/дня/года считаются идентичными. Мы никогда не будем спорить об обмене моего "30 сентября 2009" на ваше, потому что они одинаковые :-)

С другой стороны, Entity в первую очередь идентифицируется своим «ID». Например, банковские счета имеют идентификаторы — все они имеют номера счетов. Если в банке есть два счета, на каждом по 500 долларов, и номера их счетов разные, то и они тоже. Их свойства (в данном примере их баланс) не идентифицируют их и не подразумевают равенства. Бьюсь об заклад, мы бы поспорили об обмене банковскими счетами, даже если бы их балансы были одинаковыми :-)

Итак, в вашем примере я бы рассматривал поставщика как Entity, поскольку я полагаю, что каждый поставщик в первую очередь идентифицируется по его идентификатору, а не по его свойствам. Моя собственная компания имеет то же имя, что и две другие в мире, но мы не все взаимозаменяемы.

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

Теперь, что касается Aggregate Root, вы хотите сосредоточиться на жизненном цикле и управлении доступом к объектам. Учтите, что у меня есть блог со многими сообщениями, каждое из которых имеет много комментариев - где Aggregate Root (ы)? Начнем с комментариев. Есть ли смысл комментировать без поста? Вы бы создали комментарий, а затем нашли сообщение и прикрепили его к нему? Если вы удалите пост, оставите ли вы комментарии к нему? Предлагаю пост Aggregate Root с одним "листом" - комментариями. Теперь рассмотрим сам блог — его отношения с постами аналогичны отношениям между постами и комментариями. Это тоже по-моему Aggregate Root с одним "листом" - постами.

Итак, в вашем примере существует тесная связь между компанией и поставщиком, при которой, если вы удалите компанию (я знаю... у вас, вероятно, есть только один экземпляр компании), вы также удалите ее поставщиков? Если вы удалите «Старбакс» (кофейная компания в США), перестанут ли существовать все ее поставщики кофейных зерен? Все это зависит от вашего домена и приложения, но я предполагаю, что более чем вероятно, что ни один из ваших Entities не является Aggregate Roots, или, возможно, лучший способ думать о них состоит в том, что они являются совокупными корнями, каждый из которых не имеет «листьев» (нечего агрегировать). Другими словами, компания не контролирует доступ к поставщикам и не контролирует их жизненный цикл. Он просто имеет отношения «один ко многим» с поставщиками (или, возможно, «многие ко многим»).

Это подводит нас к Repositories. Repository предназначен для хранения и извлечения Aggregate Roots. У вас есть два (технически они ничего не агрегируют, но это проще, чем сказать «репозитории хранят совокупные корни или сущности, которые не являются листьями в совокупности»), поэтому вам нужно два Repositories. Один для компании и один для поставщиков.

Надеюсь, это поможет. Возможно, здесь скрывается Эрик Эванс и расскажет мне, где я отклонился от его парадигмы.

person SingleShot    schedule 01.10.2009
comment
Потрясающий ответ! Вы помогли подтвердить то, что я думал, и объяснили намного больше. Большое спасибо! Я согласен, должны быть общие ссылки на поставщиков, если они существуют, но на данный момент это будут данные, введенные пользователем, без возможности проверки того, что 2 поставщика одинаковы. Это может измениться в будущем по мере развития системы, но пока это история. Еще раз спасибо! - person Michael Cook; 01.10.2009
comment
Я согласен, что это отличное объяснение, более полезное, чем то, что я обычно нахожу в списке рассылки DDD! - person Jiho Han; 01.10.2009
comment
Это из книги (Domain Driven Design)! - person SingleShot; 09.02.2012

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

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

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

person Sam    schedule 01.10.2009