#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 для согласованности.