Обновить сущность внутри агрегата

Я читал аналогичный вопрос о SO: Как обновить сущность внутри Aggregate, но я все еще не уверен, как пользовательский интерфейс должен взаимодействовать с сущностями внутри агрегата.

Допустим, у меня есть Userс кучей Addressэс. Пользователь - это совокупный корень, а Адрес существует только в совокупности.

На веб-интерфейсе пользователь может редактировать свои адреса. По сути, происходит следующее:

  • Пользователь видит список адресов в своем веб-интерфейсе.
  • Он нажимает на адрес и перенаправляется на эту страницу: edit-address?user=1&address=2
  • На этой странице он получает форму, где он может изменить этот адрес.

Я решил обойти корень агрегата, это было бы просто:

  • Мы бы напрямую загрузили Address с этими Id
  • Мы бы обновили его, а затем сохранили

Поскольку мы хотим сделать это DDD, у нас есть разные решения:

  1. Либо мы просим пользователя получить этот адрес по идентификатору:

    address = user.getAddress(id);
    address.setPostCode("12345");
    address.setCity("New York");
    em.persist(user);

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

  2. Или мы сообщаем агрегату обновить существующий адрес:

    user.updateAddress(id, "12345", "New York");
    em.persist(user);

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

  3. Или мы рассматриваем адрес как объект значения, и мы не обновляем наш Address, а скорее удалите его и создайте заново:

    user.removeAddress(id);
    address = new Address();
    address.setPostCode("12345");
    address.setCity("New York");
    user.addAddress(address);
    em.persist(user);

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

Я почти уверен, что здесь что-то упущено, чтобы правильно понять концепцию совокупности и то, как она используется в реальных примерах, поэтому, пожалуйста, не стесняйтесь давать свои комментарии!

1 ответ

Решение

Нет, вы ничего не упускаете - в большинстве случаев лучшим вариантом будет номер 2 (хотя я бы назвал этот метод changeAddress затем updateAdress - обновление кажется не-DDD), и это независимо от того, является ли адрес объектом или объектом значения. С Ubiquitous Language вы бы предпочли сказать, что пользователь изменил свой адрес, так что именно так вы должны его смоделировать - это changeAddress метод, который решает, обновлять ли свойства (если Адрес является сущностью) или назначать совершенно новый объект (когда это VO).

В следующем примере кода предполагается наиболее распространенный сценарий - Address as VO:

    public void ChangeAddress(AddressParams addressParams)
    {
        // here we might include some validation

        address = new Address(addressParams);

        // here we might include additional actions related with changing address
        // for example marking user as required to confirm address before
        // next billing
    }

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

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

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

Другой пример - для большинства доменов Money было бы Объектом Значения - 10$ - 10$, у этого нет никакой идентичности кроме количества. Однако, если вы смоделируете домен, который имеет дело с деньгами на уровне счетов, каждый счет будет иметь свою собственную идентификацию (выраженную с помощью какого-то уникального числа), таким образом, это будет сущность.

Другие вопросы по тегам