2014-11-14 6 views
11

Доступ к репозиториям доступа к доменным службам? Или они должны работать над агрегатами/объектами, переданными им службами приложений?Может ли доступ к репозиториям доступа к доменным службам?

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

Вариант 1 использует репозитории внутри службы домена. Вариант 2 разрешает зависимости в службе приложения и передает их в TransferDomainService.

В этом примере операция проста (вычитайте деньги из одной учетной записи и добавьте ее в другую). Но если бы было вовлечено больше бизнес-правил (возможно, требуется доступ к большему количеству агрегатов)? Если применяется вариант 2, то служба приложения должна иметь представление о том, что именно требуется службе домена. Если выбран вариант 1, служба домена запрашивает репозитории для выполнения своей задачи.

(Заметки о фрагментах:. Groovy код раздеться многословие Java DDD строительных блоков, включенных в именах)

Вариант 1

class TransferApplicationService { 
    def transferDomainService 
    def customerDomainService 
    def emailNotifierInfrastructureService 

    def transfer(fromAccount, toAccount, amount) { 
     transferDomainService.transfer(fromAccount, toAccount, amount) 
     def email = customerDomainService.accountNotificationEmail(toAccount) 
     emailNotifierInfrastructureService.notifyAboutTransfer(email, amount) 
    } 
} 

class TransferDomainService { 
    def accountRepository 
    def transfer(fromAccount, toAccount, amount) { 
     def from = accountRepository.findByNumber(fromAccount) 
     def to = accountRepository.findByNumber(toAccount) 
     to.decreaseBalance(amount) 
     from.increaseBalance(amount) 
    } 
} 

Вариант 2

class TransferApplicationService { 
    def accountRepository 
    def transferDomainService 
    def customerDomainService 
    def notifierInfrastructureService 

    def transfer(fromAccount, toAccount, amount) { 
     def from = accountRepository.findByNumber(fromAccount) 
     def to = accountRepository.findByNumber(toAccount) 
     transferDomainService.transfer(from, to, amount) 
     def email = customerDomainService.accountNotificationEmail(toAccount) 
     notifierInfrastructureService.notifyAboutTransfer(email, amount) 
    } 
} 

class TransferDomainService { 
    def transfer(fromAccount, toAccount, amount) { 
     to.decreaseBalance(amount) 
     from.increaseBalance(amount) 
    } 
} 
+0

Да.Служба доменов по-прежнему является оркестром, но только ее область знаний более ограничена. – MikeSW

+0

@MikeSW вы имеете в виду под «да» «Репозитории доступа к службам доменов» или «они работают с агрегатами/сущностями, переданными им службами приложений»? – mgryszko

+0

Да к названию вопроса. – MikeSW

ответ

10

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

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

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

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

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

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

+0

Не принимайте мой образец как код как что-то взятое из производственного кода :). Я просто хотел установить контекст для вариантов Domain Service - Repository. – mgryszko

+0

@mgryszko Ну, в DDD вы не можете отвечать на фиктивные домены, а затем применять это к своему собственному домену. Все ответы всегда сводятся к «это зависит». У вас есть свод правил и рекомендаций, но ничто из того, что никогда не ставится в камень. То, что я говорю, заключается в том, что приложения-службы должны разрешать агрегаты для службы домена, если только эта утечка логики домена в службе приложения (например, обнаружение этих зависимостей основано на правилах домена). Кроме того, я говорю, что если бы вы не изменяли оба агрегата в одной транзакции, возможно, вам даже не понадобилась бы служба домена. – plalx

+2

Нет такого «правила», что только один AR должен быть изменен одной службой. – MikeSW