DDD - не выставлять геттеры во время занятий - PullRequest
0 голосов
/ 17 сентября 2018

В последнее время я много читаю о DDD. У меня были некоторые базовые знания (и я использовал их на практике), но теперь я решил (почти) перейти на 100% DDD. Конечно, я сразу столкнулся с проблемами.

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

Теперь, когда я работаю с некоторыми вариантами использования в сервисах приложений, мне приходится работать с моим корневым агрегатом, выполнять некоторую логику и, наконец, сопоставлять его с некоторым DTO для пользовательского интерфейса. Проблема в том, что для выполнения такого отображения я должен предоставить getters / setter для большинства моих атрибутов, что меня убивает. Я хочу избежать анемичной модели, предоставляя множество бизнес-методов и очень мало получателей / установщиков.

Я вижу 2 решения:

  • вводит DTO в мой уровень домена, который также является DDD, и имеет методы toDTO () в моих сущностях
  • предоставляет геттеры / сеттеры и использует его только в мапперах

Любые другие решения, как вы, люди, решаете такую ​​распространенную проблему в ваших приложениях? Я знаю, что на самом деле трудно придерживаться DDD в действительности, и это нормально - не следовать всем правилам, но я заметил, что наличие как можно меньшего числа получателей / установщиков очень сильно помогает мне в моем дизайне, но в то же время ясно, что DTO не принадлежит на домен вообще.

Ответы [ 3 ]

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

Вон Вернон имеет дело с тем, что в главе 14 («Применение») Красной книги, в разделе «Интерфейс пользователя» (стр. 512), он предлагает несколько альтернатив:

  • DTOS
  • Посредник
  • объекты полезной нагрузки домена
  • государственные представления
  • использование оптимальных вариантов запросов к хранилищу (закрыт для cqrs)
  • преобразователи данных

Надеюсь, это поможет.

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

Применяя CQRS, вы можете избежать использования геттеров в вашем AR.Кроме того, вы даже можете уменьшить количество атрибутов, которые есть в вашем AR, до тех, которые необходимы для удовлетворения некоторого инварианта.

Позвольте мне объяснить лучше.

CQRS (Разделение ответственности при выполнении командных запросов)Различает полностью операции Command и Query, которые предоставляет ваше приложение.

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

Затем событие домена (которое моделируется как DTO) используется для построения модели представления, которая содержит все данныевам нужно вернуться с ваших запросов.Модель представления - это DTO, которую легко сериализовать и отправлять по проводам.

Таким образом, ваши запросы (те, которые используются для наполнения вашего пользовательского интерфейса информацией) даже не увлажняют ваши AR.Они работают с вашей моделью представления, поэтому любые изменения в ней не влияют на ваш AR.

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

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

Проблема в том, что для выполнения такого отображения я должен предоставить getters / setter для большинства моих атрибутов, которые меня убивают.

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

Если вы хотите, чтобы агрегат был полезен, вы должны быть в состоянии извлечь из него информацию каким-то образом . Писать только базы данных не очень интересно; если на интерфейсе нет какого-либо запроса , тогда нет особого смысла помещать информацию в объект.

Допустим запрос, специфичный для домена, для получения значения из совокупности. Ключевые ограничения

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

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

    // Не делайте этого: int x = o.X (); х = х + 1; o.Y (х)

Вы можете сделать несколько вещей, чтобы код в целом выглядел «чище».

1) Пусть агрегат отвечает на запросы с объектами-значениями, а затем запрашивает у этих объектов-значений информацию, необходимую для построения DTO.

2) Передайте фабричный метод в агрегат, чтобы получить необходимые данные

<T> T query(API<T> api)

Где API<T> - это элемент сборки / фабрики, с которым агрегат может взаимодействовать.

3) иметь два отдельных интерфейса, реализованных агрегатом (один для запросов, один для команд), и предоставлять вызывающей стороне только доступ к нужному интерфейсу.

4) Иметь одну точку запроса, чтобы получить «текущее состояние» из совокупности, а затем построить все остальное из этого.

...