【问题标题】:How to integrate Repository with DDD and Spring如何将 Repository 与 DDD 和 Spring 集成
【发布时间】:2015-09-24 22:53:47
【问题描述】:

我想使用 Spring 遵循 DDD 方法创建一个应用程序。假设我有一个业务模型类Foo 和一个接口FooRepository

DDD 告诉 FooRepository 的实现应该包含在基础设施层中。

我想使用CrudRepository,但如果我在域层中定义:

public interface FooRepository extends CrudRepository<Foo, Long>{
    // Some methods
}

我打破了核心概念,即领域层(FooRepository 接口)一定不知道基础设施层(CrudRepository)。

几个月前我正在阅读有关此领域驱动设计的内容,但我还没有找到完全支持它的框架。

我怎样才能以正确的方式做到这一点?

【问题讨论】:

标签: java spring domain-driven-design ddd-repositories


【解决方案1】:

在分层架构中,通常有 3 层:applicationdomaininfrastructure

基础设施

这里我放了repository的实现。在您的情况下,这是CrudRepository 的实现,我将直接在具体类中实现,而不使用中间接口。对于仓库中单个对象的行为,我们做出任何假设,我们只是将它们放在那里并有效地检索它们。这样我们就没有领域的知识。我们只为域提供一个与之交互的接口:WarehouseRepository 的一组公共方法。

public class WarehouseRepository implements CrudRepository<Foo, Long> {
    ...
}

当您在 UnitOfWork/Transaction 中时,模型的各个部分与 WarehouseRepository 交互。在方法 adjustQuantityPlus 中,我们只看到应用程序不感兴趣并且不需要在基础架构级别知道的域逻辑。

public class SaleOrder {
    public adjustQuantityPlus(LineItemID lineItemID,
                              WarehouseRepository warehouseRepository) {
        this.lineItems.get(lineItemID).addOne(); //<-- add one to the order
        Product product = 
            warehouseRepository.findByLineItem(lineItem);
        product.minusOneFromStock(); //<-- decrease one from stock
    }
}

应用

在这里,我们开始和停止操作许多域对象的事务 (UOWork)。每个业务方法对应一个业务用例。

public class CustomerEventsManager {
    @Inject WarehouseRepository warehouseRepository;
    @Inject SaleOrderRepository saleOrderRepository;
    @Transactional
    public wantsOneMoreOf(ProductID productID, SaleOrderID saleOrderID) {
        SaleOrder saleOrder = 
            saleOrderRepository.findByID(saleOrderID)
        saleOrder.adjustQuantityPlus(productToLineItem(productID),
                                     warehouseRepository); //<-- add product
        webPage.showPromoDiscount(); //<-- show promotional advertisement
    }
}

以上代码是一笔交易,如果系统无法将产品添加到订单中,我不想给客户折扣。 adjustQuantityPlus 又是一个具有域逻辑的内部“事务”,对应用程序层隐藏。

【讨论】:

  • 层之间存在循环依赖。在您的示例中,基础设施层知道域层(因为您使用Foo)并且域层知道基础设施层(因为BarDomainObject 使用FooRepository)所以这不是一个好方法。为了避免循环依赖,你需要在域层定义一个接口存储库,所以如果你需要在其中使用一个存储库,你必须在基础设施层使用接口和一些实现。
  • 不完全是,基础设施层知道实体的结构,领域层知道实体如何工作,应用层知道实体如何交互。领域层必须了解此架构中的基础设施层。
  • Here 是概念的总结。看图
  • 是的,它甚至可以在您的图表中使用。无论如何,如果您有兴趣谈论它,我们可以打开一个聊天室。无论如何,我会尝试详细说明我的答案。
  • 我是 DDD 的新手,但我拥有高级的 OO 知识和软件开发。也许我错了,但我不明白你为什么在SaleOrder 实体中使用存储库。如果在 saleOrder.adjustQuantityPlus() 内部,您需要从 lineItem 获取产品,因此它应该知道哪个产品包含在执行 lineItem.getProduct() 或者可能将 adjustQuantityPlus() 委托给 SaleOrderService。实体应该包含业务规则、属性和与另一个实体的关系,而不是存储库。如果您需要从域层调用存储库,则应该在域服务类中进行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2021-08-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多