DAO 和 Repository 模式有什么区别?
数据访问对象 (DAO) 和存储库模式之间有什么区别?我正在开发一个应用程序,使用 Enterprise Java Beans (EJB3)、Hibernate ORM 作为基础架构,并使用领域驱动设计 (DDD) 和测试驱动开发 (TDD) 作为设计技术。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(15)
好吧,我想我可以更好地解释我在评论中添加的内容:)。
因此,基本上,您可以将它们视为相同的,尽管 DAO 是比存储库更灵活的模式。如果您想同时使用两者,则可以使用 DAO 中的存储库。我将在下面逐一解释:
存储库:
它是特定类型对象的存储库 - 它允许您搜索特定类型的对象并存储它们。通常它只会处理一种类型的对象。例如,AppleRepository
允许您执行AppleRepository.findAll(criteria)
或AppleRepository.save(juicyApple)
。
请注意,存储库使用的是域模型术语(而不是数据库术语 - 与数据如何在任何地方保存无关)。
存储库很可能将所有数据存储在同一个表中,而模式并不要求这样做。事实上,它只处理一种类型的数据,这使得它在逻辑上连接到一个主表(如果用于数据库持久性)。
DAO - 数据访问对象(换句话说 - 用于访问数据的对象)
DAO 是一个为您定位数据的类(它主要是一个查找器,但通常也用于存储数据)。该模式不限制您存储相同类型的数据,因此您可以轻松拥有一个定位/存储相关对象的 DAO。
例如,您可以轻松地让 UserDao 公开类似的方法,
Collection<Permission> findPermissionsForUser(String userId)
User findUser(String userId)
Collection<User> findUsersForPermission(Permission permission)
所有这些方法都与用户(和安全性)相关,并且可以在相同的 DAO 下指定。存储库的情况并非如此。
最后
请注意,这两种模式实际上意味着相同(它们存储数据并抽象对数据的访问,并且它们的表达都更接近域模型并且几乎不包含任何数据库引用),但它们的使用方式可能略有不同,DAO更加灵活/通用,而存储库更加具体并且仅限于类型。
DAO 和存储库模式是实现数据访问层 (DAL) 的方法。那么,我们首先从 DAL 开始。
访问数据库的面向对象应用程序必须具有一些逻辑来处理数据库访问。为了保持代码的整洁和模块化,建议将数据库访问逻辑隔离到单独的模块中。在分层架构中,这个模块就是DAL。
到目前为止,我们还没有讨论任何具体的实现:只是将数据库访问逻辑放在单独的模块中的一般原则。
现在,我们如何实施这个原则呢?嗯,一种已知的实现方法,特别是使用 Hibernate 这样的框架,就是 DAO 模式。
DAO 模式是一种生成 DAL 的方式,通常每个域实体都有自己的 DAO。例如,User
和 UserDao
、Appointment
和 AppointmentDao
等。使用 Hibernate 的 DAO 示例:http://gochev.blogspot.ca/2009/08/hibernate-generic-dao.html。
那么什么是Repository模式呢?与DAO一样,Repository模式也是实现DAL的一种方式。存储库模式的要点是,从客户端/用户的角度来看,它应该看起来或表现得像一个集合。表现得像集合的意思并不是说它必须像 那样实例化。相反,它意味着它应该支持添加、删除、包含等操作。这就是存储库模式的本质。Collection collection = new SomeCollection()
在实践中,例如在使用Hibernate的情况下,Repository模式是通过DAO来实现的。也就是说,DAL 的实例可以同时是 DAO 模式和存储库模式的实例。
存储库模式不一定是建立在 DAO 之上的东西(正如某些人可能建议的那样)。如果 DAO 设计有支持上述操作的接口,那么它就是 Repository 模式的一个实例。想想看,如果 DAO 已经提供了一组类似集合的操作,那么在它之上还需要额外的一层吗?
存储库是更抽象的面向领域的术语,是领域驱动设计的一部分,它是领域设计和通用语言的一部分,DAO 是数据访问技术的技术抽象,存储库只关心管理现有数据和工厂以创建数据。
检查这些链接:
DAO 允许以更简单的方式从存储中获取数据,隐藏丑陋的查询。
存储库也处理数据并隐藏查询等,但是存储库处理业务/域对象。
存储库将使用 DAO 从存储中获取数据,并使用该数据来恢复业务对象。
例如,DAO 可以包含一些类似的方法 -
public abstract class MangoDAO{
abstract List<Mango>> getAllMangoes();
abstract Mango getMangoByID(long mangoID);
}
并且 Repository 可以包含一些类似的方法 -
public abstract class MangoRepository{
MangoDao mangoDao = new MangDao;
Mango getExportQualityMango(){
for(Mango mango:mangoDao.getAllMangoes()){
/*Here some business logics are being applied.*/
if(mango.isSkinFresh()&&mangoIsLarge(){
mango.setDetails("It is an export quality mango");
return mango;
}
}
}
}
这教程帮助我轻松掌握主要概念。
存储库只不过是精心设计的 DAO。
ORM 以表为中心,但不是以 DAO 为中心。
无需在存储库中使用多个 DAO,因为 DAO 本身可以对 ORM 存储库/实体或任何 DAL 提供程序执行完全相同的操作,无论汽车在何处以及如何持久保存 1 个表、2 个表、n 个表、半个表、一个Web 服务、表格和 Web 服务等。
服务使用多个 DAO/存储库。
我自己的DAO,假设CarDao只处理Car DTO,我的意思是,只在输入中接受Car DTO,并且在输出中只返回car DTO或car DTO集合。
所以就像Repository一样,DAO实际上是一个IoC,对于业务逻辑来说,允许持久化接口不会被持久化策略或遗留问题吓倒。
DAO 既封装了持久化策略,又提供了与域相关的持久化接口。
对于那些不了解定义明确的 DAO 实际上是什么的人来说,存储库只是另一个词。
尝试找出 DAO 或 Repository 模式是否最适用于以下情况:
想象一下,您希望为各种类型的数据源(例如 RDBMS、LDAP、OODB、XML 存储库和平面文件)的持久机制提供统一的数据访问 API。
如果有兴趣,另请参阅以下链接:
http://www.codeinsanity .com/2008/08/repository-pattern.html
http://blog.fedecarg.com/2009/03/ 15/领域驱动设计存储库/
http://devlicio.us/blogs/casey /archive/2009/02/20/ddd-the-repository-pattern.aspx
http://en.wikipedia.org/wiki/Domain-driven_design
"="">http://msdn.microsoft.com/en-us/magazine/dd419654.aspx
如果我们考虑两种设计模式的原始定义 DAO 和存储库看起来非常相似。主要区别在于字典及其来源(Oracle 与 Fowler)。
引用:
DAO - “将数据资源的客户端接口与其数据访问机制分开”和“DAO 实现使用数据源所需的访问机制。数据源可以是持久存储(如 RDBMS)、外部服务(如 B2B 交换)、存储库(如 LDAP 数据库)或通过 CORBA Internet ORB 间协议 (IIOP) 或低级访问的业务服务套接字。”
存储库 - “使用类似集合的接口来访问域对象,在域和数据映射层之间进行中介。” “从概念上讲,存储库封装了数据存储中持久保存的一组对象以及对它们执行的操作,提供了持久层的更加面向对象的视图。存储库还支持实现干净分离和单向依赖的目标域和数据映射层之间。”
根据这些引文,这两种设计模式都调解领域层和数据层之间的通信。此外,Repository 与 ORM 相关,相反,DAO 是一个更通用的接口,用于从任何地方访问数据。
DAO 可能并不总是与 Only DataBase 显式相关,
它可能只是一个访问数据的接口,这种情况下的数据可以从 DB/Cache 甚至 REST 访问(现在不太常见,因为我们可以轻松地将它们分开相应的 Rest/IPC 客户端),
此方法中的 Repo 可以由任何 ORM 解决方案实现,如果底层缓存/Repo 发生更改,它将不会传播/影响服务/业务层。
DAO 可以接受/返回域类型。对于 Student Domain,关联的 DAO 类将是 StudentDao
StudentDao {
StudentRepository,
StudentCache,
Optional<Student> getStudent(Id){
// Use StudentRepository/StudentCache to Talk to DD & Cache
// Cache Type can be the same as Domain Type, DB Type(Entities) should be a Same/Different Type.
}
Student updateStudent(Student){
// Use StudentRepository/StudentCache to Talk to DD & Cache
// Cache Type can be the same as Domain Type, DB Type(Entities) should be a Same/Different Type.
}
}
DAO 可以接受/返回子域类型。考虑一个学生域,它有子域,比如出勤/主题,它将有一个 DAO 类 StudentDao,
StudentDao {
StudentRepository, SubjectRepository, AttendanceRepository
StudentCache, SubjectCache, AttendanceCache
Set<Subject> getStudentSubject(Id){
// Use SubjectRepository/SubjectCache to Talk to DD & Cache
}
Student addNewSubjectToStudent(ID, Subject){
// Use SubjectRepository/SubjectCache to Talk to DD & Cache
}
}
DAO 和存储库
DAO 模式和存储库模式都是将业务逻辑与数据持久逻辑分离的模式。他们
通常可以互换使用,这可能会导致混淆,但它们之间存在明显的差异。
DAO
DAO 模式要求为单个对象创建用于简单 CRUD 操作的抽象(因此称为数据访问对象)
一种。一种类型可以由具有自己的 DAO 的其他类型组成,因此 DAO 可以使用其他类型
DAO 但通常不会使用存储库。
DAO 被用作聚合根 - 通过它的主要实体
与对象集群的所有交互都应该发生,它还负责检查所有不变量和
聚合的规则,以确保聚合始终保持有效状态。
存储库
存储库模式要求创建用于 CRUD 操作的抽象(使用其他 DAO)、监听、
对一种类型的对象集合进行搜索、与聚合验证无关的附加数据访问/业务逻辑等。
存储库可以使用 DAO 或其他存储库。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
DAO
是数据持久化的抽象。存储库
是对象集合的抽象。DAO
将被认为更接近数据库,通常以表为中心。Repository
将被认为更接近域,仅处理聚合根。Repository
可以使用DAO
来实现,但你不会做相反的事情。此外,
Repository
通常是一个较窄的接口。它应该只是一个对象集合,带有Get(id)
、Find(ISpecification)
、Add(Entity)
。像
Update
这样的方法适用于DAO
,但不适用于Repository
- 当使用Repository
时,更改为实体通常由单独的工作单元来跟踪。被称为
Repository
的实现似乎很常见,它实际上更像是一个DAO
,因此我认为人们对它们之间的区别存在一些困惑。DAO
is an abstraction of data persistence.Repository
is an abstraction of a collection of objects.DAO
would be considered closer to the database, often table-centric.Repository
would be considered closer to the Domain, dealing only in Aggregate Roots.Repository
could be implemented usingDAO
's, but you wouldn't do the opposite.Also, a
Repository
is generally a narrower interface. It should be simply a collection of objects, with aGet(id)
,Find(ISpecification)
,Add(Entity)
.A method like
Update
is appropriate on aDAO
, but not aRepository
- when using aRepository
, changes to entities would usually be tracked by separate UnitOfWork.It does seem common to see implementations called a
Repository
that is really more of aDAO
, and hence I think there is some confusion about the difference between them.