Что такое совокупный корень?
Я пытаюсь понять, как правильно использовать шаблон репозитория. Центральная концепция Aggregate Root продолжает появляться. При поиске в Интернете и в Stack Overflow справки о том, что такое совокупный корень, я постоянно нахожу дискуссии о них и мертвые ссылки на страницы, которые должны содержать базовые определения.
Что такое совокупный корень в контексте шаблона хранилища ?
10 ответов
В контексте шаблона репозитория агрегатные корни являются единственными объектами, которые клиентский код загружает из репозитория.
Репозиторий инкапсулирует доступ к дочерним объектам - с точки зрения вызывающей стороны он автоматически загружает их либо в тот момент, когда загружается корень, либо когда они действительно необходимы (как при отложенной загрузке).
Например, вы можете иметь Order
объект, который инкапсулирует операции на нескольких LineItem
объекты. Ваш клиентский код никогда не загрузит LineItem
объекты непосредственно, только Order
который содержит их, что будет совокупным корнем для этой части вашего домена.
От Эванса ДДД:
AGGREGATE - это кластер связанных объектов, которые мы рассматриваем как единое целое с целью изменения данных. Каждый AGGREGATE имеет корень и границу. Граница определяет, что находится внутри АГРЕГАТА. Корень - это отдельная особая сущность, содержащаяся в АГРЕГАТЕ.
А также:
Корень - единственный член AGGREGATE, которому внешние объекты могут содержать ссылки на [.]
Это означает, что агрегатные корни являются единственными объектами, которые могут быть загружены из хранилища.
Примером является модель, содержащая Customer
сущность и Address
юридическое лицо. Мы никогда бы не получили доступ к Address
сущность непосредственно из модели, поскольку это не имеет смысла без контекста Customer
, Таким образом, мы могли бы сказать, что Customer
а также Address
вместе образуют совокупность и Customer
является совокупным корнем.
Совокупный корень - это сложное имя для простой идеи.
Главная идея
Хорошо разработанная диаграмма классов инкапсулирует ее внутренности. Точка, через которую вы получаете доступ к этой структуре, называется aggregate root
,
Внутренние элементы вашего решения могут быть очень сложными, но пользователь этой иерархии будет просто использовать root.doSomethingWhichHasBusinessMeaning()
,
пример
Проверьте эту простую иерархию классов
Как вы хотите ездить на своей машине? Выбрал лучший API
Вариант А (просто как-то работает):
car.ride();
Вариант B (пользователь имеет доступ к инерналам класса):
if(car.getTires().getUsageLevel()< Car.ACCEPTABLE_TIRE_USAGE)
for (Wheel w: car:getWheels()){
w.spin();
}
}
Если вы считаете, что вариант А лучше, то поздравляю. Вы получаете основную причину позади aggregate root
,
Совокупный корень инкапсулирует несколько классов. Вы можете управлять всей иерархией только через основной объект.
Представьте, что у вас есть объект "Компьютер", этот объект также не может существовать без объекта "Программное обеспечение" и "Оборудование". Они образуют Computer
агрегат, мини-экосистема для компьютерной части домена.
Aggregate Root - это объект материнства внутри совокупности (в нашем случае Computer
), это обычная практика, когда ваш репозиторий работает только с сущностями, которые являются Агрегированными Корнями, и эта сущность отвечает за инициализацию других сущностей.
Рассматривайте совокупный корень как точку входа в совокупность.
В коде C#:
public class Computer : IEntity, IAggregateRoot
{
public Hardware Hardware { get; set; }
public Software Software { get; set; }
}
public class Hardware : IEntity { }
public class Software : IValueObject { }
public class Repository<T> : IRepository<T> where T : IAggregateRoot {}
Имейте в виду, что аппаратное обеспечение, скорее всего, тоже будет ValueObject (не имеет собственной идентичности), рассмотрите его только в качестве примера.
Агрегат означает сбор чего-то.
корень как верхний узел дерева, откуда мы можем получить доступ ко всему, как <html>
узел в документе веб-страницы.
Блог аналогия, пользователь может иметь много постов, и каждый пост может иметь много комментариев. поэтому, если мы получим какого-либо пользователя, он может выступать в роли пользователя root для доступа ко всем связанным постам и дальнейшим комментариям этих постов. Все это вместе называется сбор или совокупность
Если вы следуете подходу, основанному на базе данных, то вы обычно объединяете корень как таблицу со стороны 1 отношения 1-много.
Самый распространенный пример - Человек. У каждого человека есть много адресов, один или несколько платежных ведомостей, счетов-фактур, записей CRM и т. Д. Это не всегда так, но в 9/10 раз больше.
В настоящее время мы работаем над платформой электронной коммерции, и у нас есть два основных корня:
- Клиенты
- Продавцы
Клиенты предоставляют контактную информацию, мы присваиваем им транзакции, транзакции получают позиции и т. Д.
Продавцы продают товары, имеют контактных лиц, страницы о нас, специальные предложения и т. Д.
Об этом заботятся Клиент и Хранилище Продавца соответственно.
Дин:
В контексте репозитория Совокупный корень является сущностью без родительской сущности. Он содержит ноль, одну или несколько дочерних сущностей, чье существование зависит от Родителя в отношении его идентичности. Это отношение "один ко многим" в репозитории. Эти Дочерние Сущности - простые Совокупности.
Внутри Агрегата есть Совокупный Корень. Агрегированный корень является родительской сущностью для всех других сущностей и объектов значений в совокупности.
Репозиторий работает на основе совокупного корня.
Более подробную информацию также можно найти здесь.
Агрегат - это место, где вы защищаете свои инварианты и форсируете согласованность, ограничивая доступ к корню совокупного мышления Не забывайте, что агрегат должен разрабатывать бизнес-правила и инварианты вашего проекта, а не отношения с базой данных. Вы не должны вводить какие-либо хранилища, и никакие запросы не допускаются.
В другом мире, в Event Sourcing, агрегат (корень) - это другое понятие. Event Sourcing может встречаться вместе с CQRS, DDD и т. Д.
В Event Sourcing агрегат - это объект, состояние (поля) которого не отображается на запись в базе данных, как мы привыкли думать в мире SQL/JPA.
Не является группой связанных сущностей.
Это группа связанных записей, как в таблице истории.
GiftCard.amount - это одно поле в агрегате GiftCard, но это поле сопоставляется со всеми событиями, такими как погашение карты (снятие денег с карты), когда-либо созданное.
Таким образом, источником данных для вашего агрегата является не запись в базе данных, а полный список событий, когда-либо созданных для этого конкретного агрегата. Мы говорим, что мы получили совокупность событий.
Теперь мы можем спросить себя, как это делается? Кто агрегирует эти события, поэтому мы все еще работаем с одним полем, например GiftCard.amount? Мы могли бы ожидать, что эта сумма будет коллекцией, а не большим десятичным числом.
Является ли механизм поиска событий, выполняющий работу, который может просто воспроизвести все события в порядке создания. Но это выходит за рамки данной темы.
В Erlang нет необходимости проводить различие между агрегатами, когда агрегат состоит из структур данных внутри состояния вместо состава ОО. Смотрите пример: https://github.com/bryanhunter/cqrs-with-erlang/tree/ndc-london