DDD中的DAO,存储库和服务

时间:2013-11-12 17:22:06

标签: domain-driven-design dao repository

在阅读了几篇文章之后,我开始理解DAO和存储库之间的区别,但我发现自己在试图理解存储库和服务之间的区别时遇到了麻烦。

对于短期而言,在OO范例中:

  • DAO :包含一个实体类的基本CRUD operations的类。它具有获取或检索底层持久存储系统的必要代码。一般来说,方法接收对象实体作为参数,但retrieve方法除外,其中使用标识符的类型是有效的。

  • 存储库:在更高级别的抽象中......通常我读过的是一种放置代码来处理聚合对象(具有子对象的对象)的操作的地方。它使用DAO来从数据库中检索对象,最后它在域中公开了一个界面" business"语言。 (但同样,我认为使用ID的数据类型是非常有效的)。示例:一个非常简单的addSomething,其中something是父项的子对象,其实例btw由存储库作为整体进行管理。

  • 服务:同样,它处于更高的抽象层次。从我不起眼的角度来看,它们是连接两个不共享父子关系的类的好地方,但与存储库一样(在抽象术语中)。示例:两个transferCash

  • 之间的方法bank accounts

所以,这是我的读物,但我在这里问上述想法是对还是不对。或者我应该如何思考。或者某些东西让我真正理解所有这些概念的不同之处。

一些消息来源:

3 个答案:

答案 0 :(得分:23)

存储库 - 就像你说的 - 是一种抽象。它们起源于Martin Fowler的Object Query Pattern。存储库和DTO都可以通过将持久化数据映射到等效的实体对象集合来简化数据库持久性。但是,通过提供对整个Aggregate Root (AG)的控制来经常隐藏客户端的大量内部状态,存储库比DAO更粗粒度。另一方面,DAO可以像专用于单个实体对象一样精细。对于存储库和DAO,通常使用Hibernate或其他对象/关系映射(ORM)框架而不是编写自己的实现。

通常,服务可以驻留在服务层中,并且可以充当功能外观,反腐败层和协调器,用于缓存和扩展。交易。它们通常是进行伐木的好地方。服务粗粒度和面向用例,例如Service.updateCustomerAdress()Service.sendOrder()。存储库对于客户来说可能过于细粒度,例如, Customer.add(…)Order.modify(…)

存储库和DAO具有相同的目的 - 永久保存数据。另一方面,服务应该不知道持久性并且不了解您的数据库。它们通常与域服务,存储库,域核心紧密配合。

答案 1 :(得分:13)

存储库是用于存储和检索Aggregate Roots (AR)的接口,而不是单个实体。您的域模型的每个AR都有一个存储库。

根据Fowler的Repository Pattern,存储库就像内存中的对象集合,这是将它们与DAO进行比较的主要区别之一。

存储库接口是域模型客户端(因此是域模型的一部分)的一种手段,可以开始使用域模型。客户端旨在从存储库中获取AR实例,在其上调用一些方法,通常会修改其内部状态,然后将其存储回存储库。

答案 2 :(得分:3)

我不确定“DAO”是什么。存储库是加载实体的抽象。你应该能够获得一个实体并保存一个,就是这样。没有查询。如果要查询某些数据,请编写查询(甚至可以在MVC操作方法中,或者使用最简单的简单抽象,允许执行某些SQL,并返回一些可以直接呈现到HTML中的DTO)。

另一方面,服务很棘手。首先,该术语过载。由DDD book by Eric Evans定义的“应用服务”存在,因为域模型中的对象不允许访问数据库,消息传递,缓存等基础设施问题。他们需要为他们完成所有这些工作并将其交给他们板块和应用服务就是这么做的。应用程序服务,不包含任何逻辑。我不希望看到ICustomerService.ChangeAddress()做除了以外的任何事情:

  1. 加载客户实体。
  2. 调用Customer.ChangeAddress(newAddress)< - 这封装了域逻辑
  3. 拯救客户。
  4. 也许发布一些活动。
  5. 如果您有一个加载客户的服务,设置它的地址属性并保存它,那么该服务实际上是一个事务脚本,而客户是一个DTO。意味着你肯定有一个漏洞抽象,可能有一个贫血的领域模型。域模型对象不应具有公共setter,并且当DDD与CQRS结合使用时,您的域模型甚至可能在主实体ID值之外根本没有任何公共状态。