Как обрабатывать зависимое поведение в доменном классе? - PullRequest
1 голос
/ 11 марта 2019

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

Мой вопрос заключается в том, как обрабатывать зависимые сценарии в DDD.Является ли ответственность вызывающей стороны вызывать методы в правильной последовательности?Или мы заставляем методы обрабатывать зависимые операции, прежде чем их собственная логика?

Ответы [ 3 ]

0 голосов
/ 13 марта 2019

С моей точки зрения, то, что вы описываете, является оркестровкой операций модели предметной области.Это работа прикладного уровня, модели слоя на домене.У вас должна быть прикладная служба, которая будет вызывать методы модели предметной области в правильной последовательности, и она также должна учитывать, оставил ли какой-либо шаг невыполненную задачу, и в таком случае указать следующий шаг для ее выполнения.

0 голосов
/ 13 марта 2019

TLDR; Прокрутите до конца ответ, но предыстория даст хороший контекст.

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

@ RobertBräutigam высказал очень хорошую мысль:

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

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

Я знаю, что это звучит неправильно в вашем случае, и я подозреваю, что вы правы. Существует явная зависимость, что не может произойти сразу, поэтому мы не можем быть концом истории. Когда у вас есть четкая зависимость от промежуточных транзакций, которые должны произойти до «конечного» состояния, мы имеем ... оркестровку (например, саги, распределенные транзакции, доменные события и все такое добро).

То, что вы описываете с файловыми операциями, распространяется на все транзакции. Манипулирование (изменение состояния) домена является транзакционным в каждой точке распределенной транзакции, но не является транзакционным в целом. Поэтому, когда @ choquero70 говорит

Вы описываете, как оркестровка операций модели домена. Это работа прикладного уровня, модели слоя на домене.

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

Каждый из этих отдельных пунктов на временной шкале является действительным моментом в состоянии вашего домена .

Итак, вернемся к вашей модели. Если вы предоставляете один интерфейс с несколькими возможными вызовами для всех шагов, то вы оставляете себя открытым для вещей, вызываемых не по порядку. Сделать это невозможным или, по крайней мере, невероятным. Оркестровка - это не только то, что нужно сделать, но и то, что нужно предотвратить. Создайте меньшие интерфейсы / классы, чтобы избежать случайного увеличения «площади поверхности» того, что могло быть случайно использовано неправильно.

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

Ваш основной алгоритм такой же: загрузка, преобразование, загрузка.

Является ли вызывающая сторона ответственным за вызов методов в правильной последовательности?

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

Или мы заставляем методы обрабатывать зависимые операции, прежде чем их собственная логика?

Если вы правильно настроили оркестровку, в этом нет необходимости. Но в любом случае имеет смысл проверить.

На заметке, каждый шаг оркестровки, который вы делаете, должен быть очень линейным по природе. Я говорю своим разработчикам с подозрением относиться к шагу оркестровки, в котором есть оператор if . Если есть , если , то, вероятно, лучше быть частью другого шага оркестровки или инкапсулироваться в бизнес-логику.

0 голосов
/ 11 марта 2019

Ответственность за вызов методов в правильной последовательности лежит на вызывающей стороне?

Это нормально, если эти методы имеют деловое значение.Например, клиент может забронировать рейс, а затем забронировать номер в отеле.Это то, что клиент понимает, и логика клиента - вызывать их в этой последовательности.С другой стороны, вставка резервирования в базу данных, затем фиксация (или что-то еще) является технической.Клиент не должен иметь дело с этим вообще.Или «инициализировать» объект, затем вызывать другие методы, затем вызывать «close».

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

Решение состоит в том, чтобы лучше смоделировать проблему.Вероятно, существует сценарий более высокого уровня использования, которого хочет добиться вызывающая сторона с помощью этой последовательности вызовов.Таким образом, вместо публикации отдельных требуемых «шагов», просто поддержите более высокий вариант использования в целом.

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

Обновление : возможная модель для упомянутого домена "Файл":

public interface LocalFile {
    RemoteFile upload();
}

public interface RemoteFile {
    RemoteFile convert(...);

    LocalFile download();
}
...