存储库查找器方法应该具有哪些职责?

时间:2014-05-23 08:26:55

标签: domain-driven-design

TL; DR

DDD存储库应该是什么:

  • 执行后续由域名服务改进的一般搜索?

findAllByPurchaseId(purchaseId)

  • 或者根据特定用例量身定制的详细搜索?

findAllOfPurchaseDueBefore(purchaseId, limitDate)

  • 做额外的简单计算(如求和)?

amountExpectedToBePaidBefore(purchaseId, limitDate)

问题的背景

我的域模型有两个聚合:

  • Purchase(purchaseId)
  • Installment(purchaseId, dueDate, amount)

在我的一项申请服务中,我必须回答有关在特定日期之前预期支付的总分期付款金额的问题。

初始InstallmentRepository实现(Groovy + Grails + GORM + Hibernate):

def findAllByPurchaseId(purchaseId) {
    Installment.executeQuery(
        'from Installment where purchaseId = :purchaseId', 
        [purchaseId: purchaseId]
    )
}

应用程序服务进一步过滤和计算:

def amountExpectedToBePaidBefore(purchaseId, limitDate) {
    def installments = installmentRepository.findAllByPurchaseId(purchaseId).
        findAll { it.dueBefore limitDate }
    installments*.amount.sum()
}

我意识到我的应用服务有域逻辑 - 它做了额外的过滤和计算。另一方面,我的存储库似乎太 DAOish - 它做了简单的聚合访问而没有任何额外的业务价值。

我考虑两个重构选项

  1. dueDate中的过滤放入存储库中,并将域中的金额加入
  2. 在存储库中执行所有操作(金额总和是一个简单的计算)
  3. 由于存储库应该模仿专门的聚合集合,而API基于无处不在的语言,因此选项 2。对我更有吸引力。

    DDD存储库应该具有哪个抽象/详细级别?

    • 是否应执行可能由许多服务使用的通用搜索?

    • 存储库查找器应该/可能是应用程序服务/用例特定吗?

    • 在存储库中进行其他(虽然简单)计算是否可以?

1 个答案:

答案 0 :(得分:2)

  1. 没有。域存储库查询通常是GetById()。这不是一个硬性规则,但这是域需要99%的时间。不要重复使用域存储库界面进行演示/报告查询。也就是说,具体类可以处理所有内容,但抽象应该根据上下文需求进行定制。

  2. 如果域名需要,则存储库方法会获得一个可以使用的条件。

  3. 如果处理不需要业务规则那么它就可以了。然而,这不是真正的存储库语义,而是恰好在DAL中实现的服务。是的,但不要将其称为存储库:)