DDD: как моделировать связь между совокупными корнями

У нас есть совокупный корень следующим образом.

@AggregateRoot
class Document {
    DocumentId id;
}

Заявление о проблеме, данное клиентом: «К документу может быть прикреплено несколько документов».

Итак, рефакторинг модели приведет к

//Design One
@AggregateRoot
class Document {
    DocumentId id;

    //Since Document is an aggregate root it is referenced by its id only
    Set<DocumentId> attachments;

    attach(Document doc);
    detach(Document doc);
}

Но одной этой модели будет недостаточно, поскольку клиент хочет сохранить некоторую метаинформацию о вложении, например, кто и когда прикрепил. Это приведет к созданию другого класса.

class Attachment {
   DocumentId mainDocument;
   DocumentId attachedDocument;
   Date attachedOn;
   UserId attachedBy;

   //no operation
} 

и мы можем снова провести рефакторинг модели документа, как показано ниже.

//Design Two
@AggregateRoot
class Document {
    DocumentId id;
    Set<Attachment> attachments;

    attach(Document doc);
    detach(Document doc);
}

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

  1. Если я выберу первый вариант, я смогу смоделировать класс Attachment как совокупный корень и использовать события для их создания всякий раз, когда прикрепляется документ. Но это не похоже на совокупный корень.
  2. Если я выберу второй вариант, то класс Attachment можно будет смоделировать как объект значения или как сущность.
  3. Или, если я использую CQRS, я могу выбрать один вариант и модель Attachment в качестве модели запроса и заполнить ее с помощью событий.

Итак, как правильно смоделировать этот сценарий? Есть ли другой способ смоделировать другой, о чем я уже говорил?


person wolverine    schedule 22.11.2017    source источник


Ответы (1)


В долгосрочной перспективе вы можете обнаружить, что передача значений, а не сущностей, упрощает управление вашим кодом. Если присоединение / отсоединение не заботится обо всем документе, тогда просто передайте те биты, которые им важны (также известный как принцип разделения интерфейса).

attach(DocumentId);
detach(DocumentId);

Одной только этой модели будет недостаточно, поскольку клиент хочет сохранить некоторую метаинформацию о прикреплении, например, кто и когда прикрепил его.

Да, в этом есть смысл.

как правильно смоделировать этот сценарий?

Предоставлено недостаточно информации (вежливый способ сказать «это зависит от обстоятельств»).

Агрегированные границы обычно обнаруживаются, глядя на поведение, а не на структуры или отношения. Является ли отношение привязки просто неизменным значением, которое вы можете добавить / удалить, или это сущность с внутренним состоянием, которое изменяется с течением времени? Если вы измените вложение, какая еще информация вам понадобится и т. Д.

person VoiceOfUnreason    schedule 22.11.2017
comment
Я передал Document вместо DocumentId, потому что Document не может быть прикреплен, если он уже прикреплен к другому Document, только для этой проверки я передаю Document. Сам класс вложения неизменен, его можно добавить или удалить, но без поведения. Можете предложить сейчас? - person wolverine; 22.11.2017
comment
Если документ может быть прикреплен только к одному другому документу, вы можете немного перевернуть свою логику и вместо родительского документа, содержащего коллекцию прикрепленных к нему документов, сделать так, чтобы каждый документ содержал ссылку на свой «родительский» документ. Это позволит вам удовлетворить ваши бизнес-требования: у каждого документа может быть только один родитель. Что касается поиска всех дочерних документов данного документа, это то, для чего нужны представления (помните, вам не нужно постоянно использовать объекты сущности домена, представления - ваш друг) - person Joe; 23.11.2017
comment
@Joe Спасибо, интересное предложение - person wolverine; 23.11.2017