Domain driven design 领域驱动设计:服务和聚合中的领域规则

Domain driven design 领域驱动设计:服务和聚合中的领域规则,domain-driven-design,business-rules,Domain Driven Design,Business Rules,当涉及多个聚合时,我对域应该如何执行业务规则表示怀疑 假设我有账户和外部账户合计: public class Account { public String getId() {...} public void add (Double amount) {} } public class ExternalAccount { public String getId() {...} public void add (Double amount) {} } 这项服务:

当涉及多个聚合时,我对域应该如何执行业务规则表示怀疑

假设我有账户和外部账户合计:

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(…)检查完整性。我相信我的设计中有一个错误,因为用户不应该做一些无效的事情。我怎样才能预防它?我的设计中的错误在哪里?

首先:不要使用
Add()
退出。DDD是关于跟踪域的。我不认为你说的是
,所以当我向账户a添加一笔负金额时,当你与产品负责人交谈时,相同的金额将添加到账户B
。添加
Widthdraw
方法


记住。编码时不涉及任何用户。程序员是。所有的程序员都会把代码搞糟

关于服务:您无法通过代码来防止这种情况。除非取款的唯一有效方法是把钱转到另一个账户。在这种情况下,您可以更改
Widthdraw()
方法,将另一个帐户作为参数

除此之外,只需向
Widthdraw
方法添加文档,并说明如果涉及两个帐户,则应使用该服务。我想任何DDD开发人员都应该知道应该使用该服务,因为这是我们在DDD中的工作方式(你和我都知道,下一个拥有DDD经验的开发人员也应该知道)。业务逻辑应该在域对象中,因此,我认为,与其将业务逻辑放在
TransferService
中,不如用更好的方式,为了避免业务逻辑泄漏到服务,需要创建名为
AccountTransfer
的新实体,其中包含
AccountFrom
AccountTo
,类似于(抱歉,我在这里使用C):

在object
AccountTransfer
中,您可能需要更多信息,如:

  • 什么时候转车
  • 什么类型的转账:通过visa、paypal
  • 要将此类填充到数据库中,您需要存储传输历史记录,以便以后跟踪它们

  • 通过这种方式,您还可以将IsValid方法作为私有方法放入
    AccountTransfer
    中。

    这里的“用户”是什么意思,用户如何调用您上面列出的代码而不调用服务?当我提到“用户”时,我指的是使用域的开发人员。开发人员可能决定不使用服务,而是直接使用聚合。除了代码重复之外,还不能保证开发人员会执行业务规则。为什么开发人员在自己创建这些服务时可能决定不使用这些服务?可能是因为开发域模型的开发人员不是使用它的人。我认为原因无关紧要。关键是这是可能的,然后模型允许在某些情况下打破业务规则。这是不应该发生的。这和使用服务没有什么区别。它仍然无法强制执行(开发人员仍然可以直接使用这些帐户)。而且,
    AccountTransfer
    并不是一个真正的域模型。它不代表一个实体。根据DDD定义,它只是一个名称奇怪的服务。@jgauffin:为什么你认为AccountTransfer不是真正的域模型?它还包含其他属性,如何时传输、何种传输。。。并将该实体填充到数据库中。这也使得服务和服务之间有所不同AccountTransfer@CuongLe“业务逻辑应该在域对象中”-如果您指的是实体,则不一定。似乎不适合任何实体或跨多个实体的域逻辑可以放在域服务中。从DDD的角度来看,它仍然算作常规域逻辑。@guillaume31:如果让域逻辑不适合任何实体,并且跨越多个实体,那么就是在制造逻辑泄漏。逻辑应该与一个实体相匹配。如果你考虑的逻辑不止一个实体,那么定义另一个实体来包装它。105-“服务是技术框架中的常见模式,但它们也可以应用于领域层。”。107-“资金转账域服务:与账户和分类账对象交互,生成适当的借项和贷项”。
    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);
            }
        }
    }