当涉及多个聚合时,我怀疑域应该如何强制执行业务规则。
假设我有帐户和外部帐户聚合:
public class Account {
public String getId() {...}
public void add (Double amount) {}
}
public class ExternalAccount {
public String getId() {...}
public void add (Double amount) {}
}
和这项服务:
public class TransferService implements TransferServiceInterface {
public void transfer (String AccountId, String ExternalAccountId, Double amount) {
Account fromAccount = accRepository.get(AccountId);
ExternalAccount toAccount = extAccRepository.get(ExternalAccountId);
transferIsValid(fromAccount, toAccount, amount);
fromAccount.add(-amount);
toAccount.add(amount);
}
}
如果转移不符合域规则,transferIsValid将抛出异常。
如何防止此模型的用户不使用服务并执行以下操作:
Account fromAccount = accRepository.get(AccountId);
ExternalAccount toAccount = extAccRepository.get(ExternalAccountId);
fromAccount.add(-amount);
toAccount.add(amount);
用户未使用该服务,并且未使用transferIsValid(...)来检查完整性。我相信我的设计中存在错误,因为用户不应该做无效的事情。我该怎样预防呢?我的设计错误在哪里?
答案 0 :(得分:4)
首先:不要使用Add()
撤回。 DDD就是关注域名。当您与产品所有者交谈时,我不认为您说So when I add a negative amount of money to account A, the equal amount will be added to account B
。添加Widthdraw
方法。
记住。编码时不涉及用户。程序员是。所有程序员都可以搞砸代码。
关于服务:您无法通过代码来防止这种情况。除非唯一有效的提款方式是将其转移到另一个账户。在这种情况下,您可以更改Widthdraw()
方法以将另一个帐户作为参数。
除此之外,只需在Widthdraw
方法中添加文档,并说如果涉及两个帐户就应该使用该服务。 imho任何DDD开发人员应该知道应该使用该服务,因为我们在DDD中做事情(你和我做了,所以下一个开发者也应该有DDD经验)。
答案 1 :(得分:1)
业务逻辑应该在域对象中,因此,我认为更好的方法是避免业务逻辑泄漏到服务,而不是将业务逻辑放在TransferService
中。名为AccountTransfer
的实体包含AccountFrom
和AccountTo
,类似于(抱歉我在这里使用C#):
public class AccountTransfer
{
Account From { get; set; }
Account To { get; set; }
// More properties
private bool IsValid(ammount)
{}
public void DoTransfer(int amount)
{
is (IsValid(ammount))
{
From.Withdraw(amount);
To.Add(amount);
}
}
}
您可能需要对象AccountTransfer
中的更多信息,例如:
通过这种方式,您还可以将AccountTransfer
中的IsValid方法作为私有方法。