Обновить сущность внутри агрегата
Я читал аналогичный вопрос о SO: Как обновить сущность внутри Aggregate, но я все еще не уверен, как пользовательский интерфейс должен взаимодействовать с сущностями внутри агрегата.
Допустим, у меня есть User
с кучей Address
эс. Пользователь - это совокупный корень, а Адрес существует только в совокупности.
На веб-интерфейсе пользователь может редактировать свои адреса. По сути, происходит следующее:
- Пользователь видит список адресов в своем веб-интерфейсе.
- Он нажимает на адрес и перенаправляется на эту страницу:
edit-address?user=1&address=2
- На этой странице он получает форму, где он может изменить этот адрес.
Я решил обойти корень агрегата, это было бы просто:
- Мы бы напрямую загрузили
Address
с этимиId
- Мы бы обновили его, а затем сохранили
Поскольку мы хотим сделать это DDD, у нас есть разные решения:
Либо мы просим пользователя получить этот адрес по идентификатору:
address = user.getAddress(id);
address.setPostCode("12345");
address.setCity("New York");
em.persist(user);
Проблема с этим подходом, IMO, в том, что объединенный корень все еще не имеет намного большего контроля над тем, что делается с адресом. Он просто возвращает ссылку на него, так что это мало чем отличается от обхода агрегата.
Или мы сообщаем агрегату обновить существующий адрес:
user.updateAddress(id, "12345", "New York");
em.persist(user);
Теперь агрегат может контролировать, что происходит с этим адресом, и может предпринимать любые необходимые действия, связанные с обновлением адреса.
Или мы рассматриваем адрес как объект значения, и мы не обновляем наш
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$, у этого нет никакой идентичности кроме количества. Однако, если вы смоделируете домен, который имеет дело с деньгами на уровне счетов, каждый счет будет иметь свою собственную идентификацию (выраженную с помощью какого-то уникального числа), таким образом, это будет сущность.