Какова цель дочерней сущности в совокупном корне? - PullRequest
0 голосов
/ 29 августа 2018

[В продолжение этого вопроса и комментариев: Если у сущности есть методы, и если да, то как предотвратить их вызов из внешнего агрегата ]

Как следует из заголовка: мне не ясно, какова действительная / точная цель сущности как ребенка в совокупности?

Согласно тому, что я читал во многих местах, это свойства сущности, которая является дочерней по отношению к совокупности:

  1. У него есть локальный идентификатор для агрегирования
  2. К нему нельзя получить доступ напрямую, но только через объединенный корень
  3. У него должны быть методы
  4. Не должен подвергаться воздействию агрегатов

На мой взгляд, это означает несколько проблем:

  1. Сущность должна быть частной для агрегирования
  2. Нам нужна копия Value-Object, доступная только для чтения, для предоставления информации от сущности (по крайней мере, для того, чтобы репозиторий мог ее прочитать, например, для сохранения в db)
  3. Методы, которые мы имеем на объекте, дублируются на Агрегате (или, наоборот, методы, которые мы должны иметь на Агрегате, которые обрабатывают объект, дублируются на объекте)

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

PS. Я хотел бы сосредоточиться на дочерней сущности на совокупности, а не на совокупностях сущностей.


[ОБНОВЛЕНИЕ в ответ на Константин Галбену ответ и комментарии]

Итак, фактически, у вас было бы что-то вроде этого?

public class Aggregate {
    ...
    private _someNestedEntity;

    public SomeNestedEntityImmutableState EntityState {
       get {
          return this._someNestedEntity.getState();
       }
    }

    public ChangeSomethingOnNestedEntity(params) {
       this._someNestedEntity.someCommandMethod(params);
    }
}

Ответы [ 5 ]

0 голосов
/ 13 сентября 2018

Я не буду писать слишком много. Просто пример. Автомобиль и снаряжение. У машины есть совокупный корень. Снаряжение является дочерней сущностью

0 голосов
/ 29 августа 2018

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

Сущность должна быть частной для агрегирования

Да. Кроме того, все состояние объекта должно быть приватным и недоступным извне.

Нам нужна копия Value-Object, доступная только для чтения, для предоставления информации от сущности (по крайней мере, для того, чтобы репозиторий мог ее прочитать, например, для сохранения в db)

Нет. Мы не раскрываем информацию, которая уже доступна. Если информация уже доступна, это означает, что кто-то уже несет ответственность за нее. Так что свяжитесь с этим объектом, чтобы сделать что-то для вас, вам не нужны данные! По сути, это то, что нам говорит Закон Деметры .

"Репозитории", как это часто используется do нужен доступ к данным, вы правы. Они плохой образец. Они часто связаны с ORM, что еще хуже в этом контексте, потому что вы теряете контроль над своими данными.

Методы, которые мы имеем на объекте, дублируются на Агрегате (или, наоборот, методы, которые мы должны иметь на Агрегате, которые обрабатывают объект, дублируются на объекте)

Хитрость в том, что вам не нужно. У каждого объекта (класса), который вы создаете, есть причина. Как описано ранее для создания дополнительной абстракции, смоделируйте часть домена. Если вы сделаете это, «агрегатный» объект, который существует на более высоком уровне абстракции, никогда не захочет предлагать те же методы, что и объекты ниже. Это означало бы, что абстракции нет вообще.

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

0 голосов
/ 29 августа 2018
  1. Сущность должна быть частной для агрегирования

Да. И я не думаю, что это проблема. Продолжайте читать, чтобы понять, почему.

  1. Нам нужна копия Value-Object, доступная только для чтения, для предоставления информации от сущности (по крайней мере, для того, чтобы репозиторий мог ее прочитать, чтобы сохранить в БД, например)

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

Сырой пример. Реальному миру потребовался бы более детальный ответ, и, возможно, performMove функция должна использовать вывод game.performMove, чтобы построить структуры propper для persistence и eventPublisher:

  public void performMove(String gameId, String playerId, Move move) {
    Game game = this.gameRepository.load(gameId); //Game is the AR
    List<event> events = game.performMove(playerId, move); //Do something
    persistence.apply(events) //events contains ID's of entities so the persistence is able to apply the event and save changes usign the ID's and changed data wich comes in the event too.
    this.eventPublisher.publish(events); //notify that something happens to the rest of the system
  }

Сделайте то же самое с внутренними сущностями. Позвольте объекту повторно выполнить данные, которые изменились, потому что его вызов метода, включая его ID, захватывает эти данные в AR и формирует пропускающий вывод для постоянства и eventPublisher. Таким образом, вам даже не нужно выставлять открытое свойство readonly для объекта с идентификатором объекта в AR и AR, а также в отношении своих внутренних данных службе приложений. Это способ избавиться от объектов мешков Геттеров / Сеттеров.

  1. Методы, которые мы имеем на сущности, дублируются на Агрегате (или наоборот, методы, которые мы должны иметь на Агрегате, которые обрабатывают сущность дублируются на сущность)

Иногда бизнес-правила, для проверки и применения, принадлежат исключительно одному объекту, а его внутреннее состояние и AR просто действуют как шлюз. Это нормально, но если вы найдете этот шаблон слишком много, то это признак неправильного дизайна AR. Может быть, внутренняя сущность должна быть АР, а не внутренней сущностью, может быть, вам нужно разделить АР на несколько АР (и одна из них - старая нерная сущность) и т. Д. Не бойтесь иметь классы, имеющие только или два метода.

В ответ на комментарии ди * зг:

Что точно делает persistance.apply (события)? это спасает весь только совокупность или субъекты?

Ни. Агрегаты и сущности являются понятиями предметной области, а не понятиями постоянства; у вас может быть хранилище документов, хранилище столбцов, реляционное и т. д., которое не должно совпадать с 1: 1 вашего домена. Вы не читаете Агрегаты и сущности с упорства; Вы строите агрегаты и сущности в памяти с данными, считанными с постоянства. Сама совокупность не нуждается в сохранении, это просто возможная деталь реализации. Помните, что агрегат - это просто конструкция для организации бизнес-правил, а не представление о состоянии.

Ваши события имеют контекст (намерения пользователя) и данные, которые были изменены (вместе с идентификатором, необходимым для идентификации вещей в постоянстве), поэтому невероятно легко написать функцию apply в слое постоянства, который знает, т.е. какую инструкцию sql в случае реляционной БД, что выполнить, чтобы применить событие и сохранить изменения.

Не могли бы вы привести пример, когда и почему его лучше (или даже неизбежно?) использовать дочернюю сущность вместо отдельной AR, на которую ссылается его идентификатор в качестве объекта значения?

Почему вы разрабатываете и моделируете класс с насыщенностью и поведением?

Для абстрагирования, инкапсуляции, повторного использования и т. Д. Базовый SOLID дизайн. Если у сущности есть все необходимое для обеспечения правил и инвариантов домена для операции, тогда эта сущность является AR для этой операции. Если вам нужны дополнительные проверки правил домена, которые не могут быть выполнены объектом (т. Е. У объекта недостаточно внутреннего состояния, чтобы выполнить проверку, или он не вписывается в сущность и то, что представляет), то вам придется перепроектировать; Иногда может потребоваться смоделировать агрегат, который выполняет дополнительные проверки правил домена, и делегировать проверку других правил домена внутренней сущности, иногда можно изменить сущность для включения новых вещей. Это слишком зависит от контекста домена, поэтому я не могу сказать, что существует фиксированная стратегия редизайна.

Имейте в виду, что вы не моделируете агрегаты и сущности в своем коде. Вы моделируете только классы с поведением для проверки правил домена и состояния, необходимого для проверки и ответа с изменениями. Эти классы могут выступать в качестве агрегатов или объектов для различных операций. Эти термины используются только для того, чтобы помочь связать и понять роль класса в контексте каждой операции. Конечно, вы можете оказаться в ситуации, когда операция не вписывается в сущность, и вы можете смоделировать агрегат с помощью V.O. идентификатор персистентности и все в порядке (к сожалению, в DDD, не зная контекста домена, по умолчанию почти все в порядке).

Хочешь больше просветления от кого-то, кто объясняет вещи намного лучше меня? (не быть носителем английского языка - это препятствие для решения этих сложных вопросов) Посмотрите здесь:

https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1 http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2 http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3

0 голосов
/ 29 августа 2018
  1. У него есть локальный идентификатор для агрегирования

В логическом смысле, возможно, но конкретная реализация этого с постоянством означает, что у нас часто бывают излишне сложные.

  1. Нам нужна копия Value-Object только для чтения, чтобы предоставить информацию из сущность (по крайней мере, для хранилища, чтобы иметь возможность прочитать его для того, чтобы сохранить в БД, например)

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

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

Итак, почему у нас вообще есть сущность, а не только объекты-значения?

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

  • Инкапсуляция операций
  • Инвариантное выполнение на уровне агрегатов
  • Доступ для чтения
  • Доступ для записи
  • целостность данных объекта или VO

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

0 голосов
/ 29 августа 2018

Этих вопросов у вас нет в архитектуре CQRS, где модель записи (агрегат) отличается от модели чтения. В плоской архитектуре Aggregate должен предоставлять методы чтения / запроса, иначе это будет бессмысленно.

  1. Сущность должна быть частной для агрегирования

Да, таким образом, вы четко выражаете тот факт, что они не предназначены для внешнего использования.

  1. Нам нужна копия Value-Object, доступная только для чтения, для предоставления информации от сущности (по крайней мере, для того, чтобы репозиторий мог ее прочитать, например, для сохранения в db)

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

Сущности можно просматривать / реализовывать как объекты с неизменным идентификатором и объектом Value, представляющим его состояние, что-то вроде этого (в псевдокоде):

class SomeNestedEntity
{
    private readonly ID;
    private SomeNestedEntityImmutableState state;

    public getState(){ return state; }
    public someCommandMethod(){ state = state.mutateSomehow(); }
}

Так ты видишь? Вы можете безопасно вернуть state вложенной сущности, поскольку она неизменна. Там может быть некоторая проблема с Законом Деметры , но это решение, которое вам придется принять; если вы нарушаете его, возвращая состояние, вы делаете код проще для написания в первый раз, но связь увеличивается.

  1. Методы, которые мы имеем на объекте, дублируются на Агрегате (или, наоборот, методы, которые мы должны иметь на Агрегате, которые обрабатывают объект, дублируются на объекте)

Да, это защищает инкапсуляцию Агрегата, а также позволяет Агрегату защищать его инварианты.

...