DDD - не раскрывать геттеры при наличии класса сопоставления

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

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

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

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

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

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

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

Juan 17.09.2018 19:53

Да точно, но какая альтернатива?

pzeszko 17.09.2018 19:58

Я могу сказать вам, что делаю, но не уверен, что это именно тот ответ, который вы ищете. Я помещаю DTO на уровень представления. На уровне обслуживания работайте с моделью и во время возврата результата создайте и заполните DTO. Для получения данных из модели я использую геттеры. И у DTO есть все общедоступные атрибуты без методов.

Juan 17.09.2018 20:03

Вам не нужны сеттеры, просто геттеры, чтобы прочитать это

Tseng 18.09.2018 15:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
547
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

The problem is that to perform such mapping I have to provide getters/setter for most of my attributes which kills me.

Ага - я долго боролся с этим. Настоящий ответ заключается в том, что магии нет.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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