Что принадлежит совокупному корню - PullRequest
32 голосов
/ 07 мая 2009

Это практический вопрос о дизайне, управляемом доменом:

Концептуально, я думаю, что я получаю Совокупные корни, пока не пойду, чтобы определить их.

У меня есть сущность Сотрудник, которая появилась как Совокупный корень. В Бизнесе некоторым сотрудникам могут быть зарегистрированы нарушения, связанные с работой:

Сотрудник ----- * Нарушения

Поскольку не все сотрудники подвержены этому, я думаю, что нарушения не будут частью совокупности сотрудников, верно?

Итак, когда я хочу работать с Сотрудниками и связанными с ними нарушениями, это два отдельных взаимодействия Репозитория с какой-либо Службой?

Наконец, когда я добавляю Нарушение, это метод на Объекте Сотрудника? Спасибо за помощь!

Ответы [ 7 ]

25 голосов
/ 08 мая 2009

После даже БОЛЬШЕ исследований я думаю, что у меня есть ответ на мой вопрос.

Пол Стовелл получил этот слегка отредактированный ответ на аналогичный вопрос на доске объявлений DDD . Замените «Заказчик» на «Сотрудник», а «Заказ» на «Нарушение», и вы получите идею.

Только потому, что отзывы клиентов Заказ не обязательно означает, что порядок падает в пределах совокупного корня Клиента. Адреса клиента могут, но заказы могут быть независимыми (для Например, у вас может быть услуга, которая обрабатывает все новые заказы независимо от того, кто клиент есть. Нужно идти Заказчик-> Заказы не имеет смысла в этот сценарий).

С точки зрения домена, вы можете даже поставить под сомнение действительность тех, ссылки (у клиента есть ссылка на список заказов). Как часто вы будете на самом деле нужно все заказов для покупатель? В некоторых системах это делает смысл, но в других, один клиент может сделать много заказов. Скорее всего Вы хотите заказы для клиента между диапазон дат или заказы для клиента которые еще не обработаны или заказы которые не были оплачены, и так далее. Сценарий, в котором вам понадобится все из них могут быть относительно редкими. Тем не менее, гораздо более вероятно, что при работе с заказом вы будете хочу информацию о клиенте. Так в код, Order.Customer.Name полезен, но Customer.Orders[0].LineItem.SKU - наверное не очень полезно. Конечно, это полностью зависит от вашего бизнеса домен.

Другими словами, обновление клиента не имеет ничего общего с обновлением заказов. А заказы или нарушения в моем случае могут рассматриваться независимо от Клиентов / Сотрудников.

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

EDIT ** Здесь, в моем Домене, есть морщина: нарушения не имеют поведения. Они в основном записи событий, которые произошли. Еще не уверен насчет последствий, которые это имеет.

21 голосов
/ 01 апреля 2010

Эрик Эван заявляет в своей книге, Домен-управляемый дизайн: решение сложностей в основе программного обеспечения ,

AGGREGATE - это кластер связанных объектов, который мы рассматриваем как единое целое с целью изменения данных .

Здесь есть 2 важных момента:

  1. Эти объекты должны рассматриваться как «единица».
  2. В целях «изменения данных».

Я полагаю, что в вашем сценарии Employee и Violation не обязательно являются единым целым, тогда как в примере Order и OrderItem они являются частью единого целого.

Еще одна вещь, которая важна при моделировании границ аггрегата, - есть ли у вас какие-либо инварианты в вашей совокупности. Инварианты - это бизнес-правила, которые должны быть действительны в пределах «целого» агрегата. Например, что касается примера Order и OrderItem, у вас может быть инвариант, в котором говорится, что общая стоимость заказа должна быть меньше предварительно определенной суммы. В этом случае, всякий раз, когда вы хотите добавить OrderItem в Заказ, этот инвариант должен быть принудительно установлен, чтобы убедиться, что ваш Заказ действителен. Однако в вашей проблеме я не вижу никаких инвариантов между вашими сущностями: сотрудник и нарушение.

Такой короткий ответ:

Я считаю, что сотрудник и нарушение относятся к двум отдельным совокупностям. Каждый из этих объектов также имеет свои собственные совокупные корни. Таким образом, вам нужно 2 репозитория: EmployeeRepository и ViolationRepository.

Я также считаю, что вы должны иметь однонаправленную связь от Нарушения к Сотруднику. Таким образом, каждый объект нарушения знает, кому он принадлежит. Но если вы хотите получить список всех нарушений для конкретного сотрудника, то вы можете задать ViolationRepository:

var list = repository.FindAllViolationsByEmployee(someEmployee);
2 голосов
/ 08 января 2012

Вы говорите, что у вас есть сотрудник и нарушения, и каждое нарушение само по себе не имеет никакого поведения. Из того, что я могу прочитать выше, мне кажется, что у вас может быть два совокупных корня:

  • Сотрудник
  • Нарушения со стороны сотрудников (назовите это EmployeeViolationCard или EmployeeViolationRecords)

EmployeeViolations идентифицируется тем же идентификатором сотрудника и содержит коллекцию объектов нарушений. Вы получаете поведение сотрудника и нарушения, разделенные таким образом, и вы не получаете объект нарушения без поведения.

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

1 голос
/ 25 мая 2010

Я вообще согласен с Мошем в этом. Однако имейте в виду понятие транзакций с точки зрения бизнеса. Таким образом, я на самом деле понимаю, что «с целью изменения данных» означает «с целью транзакции (транзакций)».

Репозитории являются представлениями модели предметной области. В доменной среде эти «представления» действительно поддерживают или представляют бизнес-функцию или возможность - транзакцию. В данном случае Сотрудник может иметь одно или несколько нарушений, и, если это так, являются аспектами транзакции (транзакций) в определенный момент времени. Рассмотрим ваши варианты использования.

Сценарий: «Сотрудник совершает действие, которое является нарушением рабочего места». Это тип бизнес-события (то есть транзакция или часть более крупной, возможно, распределенной транзакции), которая произошла. Доменный объект, подверженный влиянию корня, на самом деле можно рассматривать с нескольких точек зрения, поэтому он сбивает с толку. Но следует помнить о поведении, которое относится к бизнес-транзакциям, поскольку вы хотите, чтобы ваши бизнес-процессы моделировали реальный мир как можно точнее. С точки зрения отношений, как и в реляционной базе данных, ваша концептуальная модель предметной области должна фактически указывать это уже (т.е. ассоциативность), которую часто можно прочитать в любом направлении:

Сотрудник <---- совершает ------- совершил ----> Нарушение

Таким образом, для этого варианта использования было бы справедливо сказать, что это транзакция, имеющая дело с нарушениями, и что корневая (или "основная" сущность) является нарушением. Тогда это будет ваш совокупный корень, на который вы будете ссылаться для этой конкретной бизнес-деятельности или бизнес-процесса. Но это не означает, что для другой операции или процесса у вас не может быть совокупного корня Employee, такого как «новый процесс сотрудника». Если вы позаботитесь о том, чтобы циклические ссылки не оказывали негативного влияния и не могли обходить модель вашего домена несколькими способами. Однако я предупрежу, что управление этим вопросом должно быть продумано и обработано вашим контроллером в вашей области бизнеса или любым другим аналогом, который у вас есть.

В сторону: если рассматривать шаблоны (например, MVC), хранилище является представлением, доменные объекты являются моделью, и, следовательно, следует также использовать некоторую форму шаблона контроллера. Как правило, контроллер объявляет конкретную реализацию и доступ к репозиториям (коллекции совокупных корней).

В мире доступа к данным ...

Используя LINQ-To-SQL в качестве примера, DataContext будет контроллером, отображающим представление сущностей Customer и Order. Представление представляет собой не декларативный, ориентированный на фреймворк тип таблицы (грубый эквивалент репозитория). Обратите внимание, что представление сохраняет ссылку на свой родительский контроллер и часто проходит через контроллер, чтобы контролировать, как / когда представление материализуется. Таким образом, контроллер - ваш поставщик, который заботится о картографировании, трансляции, гидратации объектов и т. Д. Затем модель является вашими POCO данных. Довольно типичный паттерн MVC.

Используя N / Hibernate в качестве примера, ISession будет контроллером, отображающим представление сущностей Customer и Order посредством session.Enumerable (string query) или session.Get (идентификатор объекта) или session.CreateCriteria (typeof) (Заказчик)). Список ()

В мире бизнес-логики ...

Customer { /*...*/ }

Employee { /*...*/ }

Repository<T> : IRepository<T>
              , IEnumerable<T>
              //, IQueryable<T>, IQueryProvider //optional

{ /**/ }

BusinessController {
 Repository<Customer>  Customers { get{ /*...*/ }} //aggregate root
 Repository<Order> Orders { get{ /*...*/ }} // aggregate root
}

В двух словах, пусть ваши бизнес-процессы и транзакции будут руководством, и пусть ваша бизнес-инфраструктура естественным образом развивается по мере того, как процессы / действия реализуются или реорганизуются. Кроме того, предпочитайте комбинируемость традиционному дизайну черного ящика. Когда вы доберетесь до сервис-ориентированных или облачных вычислений, вы будете рады, что сделали это. :)

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

Это зависит. Изменяет ли / добавляет / удаляет насилие какую-либо часть сотрудника - например, Вы сохраняете количество нарушений или количество нарушений в течение последних 3 лет в отношении сотрудника?

0 голосов
/ 22 мая 2012

немного ортогональный вопрос, чтобы проверить понимание здесь, возвращаясь к Order ... Например, OrderItem, в системе может быть аналитический модуль, который хочет напрямую просматривать OrderItems, то есть получать все orderItems для определенного продукта или весь заказ элементы, превышающие некоторое заданное значение и т. д., имеет ли много таких примеров использования и доводит «совокупный корень» до крайности, можем ли мы утверждать, что OrderItem сам по себе является другим совокупным корнем ??

0 голосов
/ 15 октября 2009

Мне было интересно, какой будет вывод?

«Нарушения» становятся корневой сущностью. На «нарушения» будет ссылаться корневая сущность «работник». то есть нарушения репозитория <-> репозиторий сотрудников

Но вы запутались в том, чтобы сделать нарушения корневыми объектами, потому что они не ведут себя.

Но является ли «поведение» критерием для определения в качестве корневого объекта? Я так не думаю.

...