Агрегат домена DI в вызовах методов

#domain-driven-design

Вопрос:

У меня есть агрегат под названием Payment , и я предоставляю вызываемый метод Capture . Из контроллера API я вызываю агрегат следующим образом:

 var payment = _mapper.Maplt;Paymentgt;(request); // auto mapper var response = await payment.Capture(_paymentCaptureDecorator); // decorator injected into controller  

Вопрос, который у меня есть, я использую шаблон декоратора, чтобы помочь мне с этим потоком вызовов, поскольку он:

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

Во всех 3 декораторах они вызывают агрегат, поскольку единственная задача декоратора-выполнить некоторое сопоставление и вызвать агрегат. Например:

 public class AcquirerDecorator : IPaymentCaptureDecorator {  private readonly IPaymentCaptureDecorator _decorator;  private readonly IAcquirerAdapter _acquirerAdapter;  private readonly IMapper _mapper;   public AcquirerDecorator(  IPaymentCaptureDecorator decorator,  IAcquirerAdapter acquirerAdapter,  IMapper mapper)  {  _decorator = decorator;  _acquirerAdapter = acquirerAdapter;  _mapper = mapper;  }    public async Tasklt;PaymentResponsegt; Execute(Payment payment)  {  var acquirerRequest = _mapper.Maplt;AcquirerRequestDtogt;(payment);  await payment.AcquireFunds(_acquirerAdapter, acquirerRequest);  return await _decorator.Execute(payment);  } }  

Затем совокупность делает это:

 public async Task AcquireFunds(IAcquirerAdapter acquirerAdapter, AcquirerRequestDto acquirerRequest) {  AcquirerResponse = await acquirerAdapter.CaptureFunds(acquirerRequest); // sets state on aggregate }  // Called by another decorator public async Task Save(ISavePaymentCommand savePaymentCommand, PaymentTransactionEntity entity) {  Card.Sanitise(); // modify state of the aggregate removing sensitive card info  if (AcquirerResponse.IsSuccessful)  {  await savePaymentCommand.Execute(entity);  } }  

Это позволяет мне использовать инъекцию конструктора в декораторе, а затем передавать зависимости в агрегат.

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

Это совершенно нормально, что нужно делать?

Комментарии:

1. «Это совершенно нормально, что ты делаешь?» Я бы сказал, что это не так. Модель домена в идеале должна быть свободна от зависимостей от процесса, следовательно, не должна взаимодействовать со шлюзами, базами данных и т. Д. даже под маской интерфейса. Модель предметной области должна обрабатывать переходы в чистое состояние, а службы на границах системы отвечают за внешние побочные эффекты. Проверяя приведенный выше код, я чувствую, что он чрезвычайно запутан в инфраструктуре и технических вопросах, а бизнес — процессы потеряны.

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

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

4. Агрегат отвечает за согласованность данных в пределах своей собственной границы. Если AR обращается к базе данных или выполняет побочные эффекты через сотрудников, то он действует на данные, которые он не контролирует. Вообще говоря, у вас может быть AR, который переходит в состояние и запускает событие, которое записывается в том же TX, что и переход состояния. Затем событие будет обработано обработчиком инфраструктуры обмена сообщениями и т.д.

5. Например, у вас может быть Payment это awaiting processing , потом, когда карточки информация предоставляется ты попытаешься это процесс payment.process() , который, возможно, срабатывает PaymentProcessingStarted даже тогда, обрабатываются процессором, который делает побочных эффектов и ждет подтверждения от которых он называет payment.confirm() отметить платеж как завершенный или, возможно, payment.reject если бы это придумывали не пройти. Я мало что знаю об обработке платежей, поэтому термины, которые я использовал, могут не иметь смысла, но идея состоит в том, чтобы извлечь побочные эффекты на границе системы и использовать ARs для согласованности.