DDD存储库的优缺点

时间:2009-12-29 16:57:07

标签: domain-driven-design repository-pattern

优点:

  • 存储库隐藏复杂查询。
  • 存储库方法可用作事务边界。
  • ORM很容易被嘲笑

缺点:

  • ORM框架已经提供了类似于持久对象的接口的集合,存储库的意图是什么。因此,存储库会给系统增加额外的复杂性。
  • 使用findBy方法时的组合爆炸。使用Criteria对象,查询或示例对象可以避免这些方法。但要做到这一点,不需要存储库,因为ORM已经支持这些查找对象的方法。
  • 由于存储库是聚合根的集合(在DDD意义上),因此即使只修改了子对象,也必须创建并传递聚合根。

问题:

  • 你知道什么是利弊?
  • 您是否建议使用存储库? (为什么或为什么不呢?)

3 个答案:

答案 0 :(得分:8)

存储库的主要观点(如单一责任原则)是抽象获取具有标识的对象的概念。随着我对DDD的熟悉程度越来越高,我认为将存储库视为主要关注数据持久性而不是实例化对象并坚持其身份的工厂,我认为没有用。

当您使用ORM时,您应该以尽可能有限的方式使用他们的API,给自己一个可能是特定于域的外观。因此,无论您的域名仍然只是看到存储库。另一方面它有ORM的事实是“实现细节”。

答案 1 :(得分:8)

Repository通过隐藏基于无所不在的语言的接口背后的数据访问细节,使域模型成为焦点。在设计存储库时,您专注于域概念,而不是数据访问。从DDD的角度来看,直接使用ORM API就等同于直接使用SQL。

这是存储库在订单处理应用程序中的样子:

List<Order> myOrders = Orders.FindPending()

请注意,没有像“条件”或“查询”这样的数据访问术语。内部“FindPending”方法可以使用Hibernate Criteria或HQL实现,但这与DDD无关。

方法爆炸是一个有效的问题。例如,您最终可能会使用多种方法:

    Orders.FindPending()
    Orders.FindPendingByDate(DateTime from, DateTime to)
    Orders.FindPendingByAmount(Money amount)
    Orders.FindShipped()
    Orders.FindShippedOn(DateTime shippedDate)
    etc

这可以通过使用规范模式来改进。例如,您可以拥有一个类

class PendingOrderSpecification{
    PendingOrderSpecification WithAmount(Money amount);
    PendingOrderSpecification WithDate(DateTime from, DateTime to)
    ...
}

所以存储库看起来像这样:

Orders.FindSatisfying(PendingOrderSpecification pendingSpec)
Orders.FindSatisfying(ShippedOrderSpecification shippedSpec)

另一个选择是为待处理和已发货订单设置单独的存储库。

答案 2 :(得分:7)

存储库实际上只是一个抽象层,就像一个接口。当您想要解耦数据持久性实现(即数据库)时,可以使用它。

我想如果您不想解耦DAL,那么您不需要存储库。但这样做有很多好处,例如可测试性。

关于“Find”方法的组合爆炸:在.NET中,您可以返回IQueryable而不是IEnumerable,并允许调用客户端对其运行Linq查询,而不是使用Find方法。这为客户提供了灵活性,但牺牲了提供定义明确,可测试的界面的能力。从本质上讲,你可以为另一种利益换取一套利益。