Как обрабатывать исключения в DCI
Представьте, что у вас есть контекст, который обрабатывает денежные переводы между учетными записями пользователей.
class Account < ActiveRecord::Base
belongs_to :user
end
class MoneySender < SimpleDelegator
class NotEnoughBalanceError < StandardError ; ; end
def initialize(account)
super(account)
end
def send_money(destination_account, amount)
raise NotEnoughBalanceError unless can_send?(amount)
self.transaction do
self.balance -= amount
destination_account.balance += amount
end
self.balance
end
def can_send?(amount)
self.balance >= amount
end
end
class HandleMoneyTransferContext
def initialize(source, destination, amount)
@source = source
@destination = destination
@amount = amount
end
def transfer
sender = MoneySender.new(@source
sender.send_money(@destination, @amount)
end
end
И денежные переводы запускаются веб-приложением и контроллером рельсов, который обрабатывает эти операции, что-то вроде этого
class AccountsController < AplicationController
def transfer
source = Account.find(params[:id])
destination = Account.find(params[:destination_account])
HandleMoneyTransferContext.new(source, destination, params[:amount]).transfer
render 'success_page'
rescue MoneySender::NotEnoughBalanceError => e
flash[:error] = t(accounts.transfer.not_enough_money)
render 'error_page', status: 400
end
end
Итак, мой вопрос: нормально ли, чтобы контекст вызывал исключения? Должен ли я поймать исключение роли в контексте и вызвать исключение контекста? (Пользователи контекста не должны знать, какие роли используются). Есть ли лучшее решение?
Спасибо
1 ответ
Контекст - это просто объект (да, есть ограничения, поэтому не все объекты являются контекстами), и в рамках операции объекта есть некоторые исключения в порядке. Например, ArgumentNil может быть действительным, если вместо того, что должно было быть RolePlayer, будет nil. Итак, чтобы ответить на ваш вопрос. Так что да, контекст может выдавать исключения, если они связаны с системными операциями, которые инкапсулирует контекст.
Тем не менее, я не вижу много DCI в вашем примере кода. Например, в контексте нет ролевых методов, и кажется, что фактическое поведение принадлежит классу, а не роли или объекту. На сайте fulloo.info есть пример перевода денег, а также один из примеров бордового камня. Вы можете прочитать больше об использовании maroon для создания DCI в ruby (хотя синтаксис был упрощен после написания этой статьи вместе с примерами, он все же должен быть хорошей отправной точкой)