【Spring】DAO 和 Repository 的区别

DAO 和 Repository 的区别

  • 1.概述
  • 2.DAO 模式
    • 2.1 User
    • 2.2 UserDao
    • 2.3 UserDaoImpl
  • 3.Repository 模式
    • 3.1 UserRepository
    • 3.2 UserRepositoryImpl
  • 4.具有多个 DAO 的 Repository 模式
    • 4.1 Tweet
    • 4.2 TweetDao 和 TweetDaoImpl
    • 4.3 增强 User 域
    • 4.4 UserRepositoryImpl
  • 5.比较两种模式
  • 6.结论

1.概述

通常,Repository 和 DAO 的实现被认为是可互换的,特别是在 以数据为中心 的应用程序中。这造成了对它们差异的混淆。

在本文中,我们将讨论 DAO 和 Repository 模式之间的差异。

在这里插入图片描述

2.DAO 模式

数据访问对象Data Access ObjectDAO)模式是数据持久性的抽象,被认为更接近于底层存储,而底层存储通常以表为中心。因此,在许多情况下,我们的 DAO 与数据库表匹配,允许更直接的方式从存储中 发送/检索 数据,从而隐藏丑陋的查询。

让我们来看看 DAO 模式的简单实现。

2.1 User

首先,让我们创建一个基本的 User 域类。

public class User {private Long id;private String userName;private String firstName;private String email;// getters and setters
}

2.2 UserDao

然后,我们将创建 UserDao 接口,该接口为 User 域提供简单的 CRUD 操作。

public interface UserDao {void create(User user);User read(Long id);void update(User user);void delete(String userName);
}

2.3 UserDaoImpl

最后,我们将创建实现 UserDao 接口的 UserDaoImpl 子类。

public class UserDaoImpl implements UserDao {private final EntityManager entityManager;@Overridepublic void create(User user) {entityManager.persist(user);}@Overridepublic User read(long id) {return entityManager.find(User.class, id);}// ...
}

在这里,为了简单起见,我们使用 JPA EntityManager 接口与底层存储交互,并为用户域提供数据访问机制。

3.Repository 模式

根据 Eric Evans 的《领域驱动设计》:Repository 是一种封装存储、检索和搜索行为的机制,它模拟对象的集合

同样,根据《企业应用架构模式》,它使用类似于集合的接口访问领域对象,在 领域层数据映射层 之间进行调解。换句话说,Repository 也处理数据并隐藏查询,与 DAO 类似。不过,它位于更高层次,更接近应用程序的业务逻辑。

因此,Repository 可以使用 DAO 从数据库获取数据并填充域对象。或者,它可以准备域对象中的数据,并使用 DAO 将其发送到存储系统以实现持久性。

让我们看看 User 域的 Repository 模式的简单实现。

3.1 UserRepository

首先,让我们创建用户存储库接口。

public interface UserRepository {User get(Long id);void add(User user);void update(User user);void remove(User user);
}

在这里,我们添加了一些常用方法,如 getaddupdateremove,以处理对象集合。

3.2 UserRepositoryImpl

然后,我们将创建 UserRepositoryImpl 类,提供 UserRepository 接口的实现。

public class UserRepositoryImpl implements UserRepository {private UserDaoImpl userDaoImpl;@Overridepublic User get(Long id) {User user = userDaoImpl.read(id);return user;}@Overridepublic void add(User user) {userDaoImpl.create(user);}// ...
}

在这里,我们使用 UserDaoImpl 从数据库中 发送/检索 数据。

到目前为止,我们可以说 DAO 和 Repository 的实现看起来非常相似,因为 User 类是一个 Anemic Domain。而且,Repository 只是数据访问层(DAO)的另一层。

🚀 只包含数据,不包含业务逻辑的类,就叫作 贫血模型(Anemic Domain Model)。贫血模型将数据与操作分离,破坏了面向对象的封装特性,是一种典型的面向过程的编程风格。

但是,DAO 似乎是 访问数据 的完美候选者,Repository 是 实现业务用例 的理想方式。

4.具有多个 DAO 的 Repository 模式

为了清楚地理解最后一句话,让我们加强 User 域来处理业务用例。

想象一下,我们想通过聚合一个用户的 Twitter 推文、Facebook 帖子等,为他准备一份社交媒体档案。

4.1 Tweet

首先,我们将创建具有一些保存推文信息的属性的 Tweet 类:

public class Tweet {private String email;private String tweetText;    private Date dateCreated;// getters and setters
}

4.2 TweetDao 和 TweetDaoImpl

然后,与 UserDao 类似,我们将创建允许获取推文的 TweetDao 界面:

public interface TweetDao {List<Tweet> fetchTweets(String email);    
}

同样,我们将创建 TweetDaoImpl 类,该类提供 fetchTweets 方法的实现:

public class TweetDaoImpl implements TweetDao {@Overridepublic List<Tweet> fetchTweets(String email) {List<Tweet> tweets = new ArrayList<Tweet>();//call Twitter API and prepare Tweet objectreturn tweets;}
}

在这里,我们将调用 Twitter API,使用用户的电子邮件获取其所有推文。

因此,在这种情况下,DAO 提供了一种使用第三方 API 的数据访问机制。

4.3 增强 User 域

最后,让我们创建 User 类的 UserSocialMedia 子类,以保留 Tweet 对象的列表。

public class UserSocialMedia extends User {private List<Tweet> tweets;// getters and setters
}

在这里,我们的 UserSocialMedia 是一个复杂的域,其中包含 User 域的属性。

4.4 UserRepositoryImpl

现在,我们将升级我们的 UserRepositoryImpl 类,以提供 User 域对象以及推文列表。

public class UserRepositoryImpl implements UserRepository {private UserDaoImpl userDaoImpl;private TweetDaoImpl tweetDaoImpl;@Overridepublic User get(Long id) {UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);List<Tweet> tweets = tweetDaoImpl.fetchTweets(user.getEmail());user.setTweets(tweets);return user;}
}

在这里,UserRepositoryImpl 使用 UserDaoImpl 提取用户数据,并使用 TweetDaoImpl 提取用户的推文。

然后,它聚合两组信息,并提供 UserSocialMedia 类的域对象,该对象对于我们的业务用例非常方便。因此,存储库依赖于 DAO 来访问来自各种源的数据。

同样,我们可以增强我们的用户域以保留 Facebook 帖子列表。

5.比较两种模式

现在我们已经看到了 DAO 和 Repository 模式的细微差别,让我们总结一下它们的区别:

  • DAO 是数据持久性的抽象。但是,Repository 是对象集合的抽象。
  • DAO 是一个较 级别的概念,更接近 存储系统。但是,Repository 是一个更 层次的概念,更接近 域对象
  • DAO 作为 数据映射/访问层 工作,隐藏丑陋的查询。但是,Repository 是 数据访问层 之间的一层,隐藏了整理数据和准备域对象的复杂性。
  • DAO 不能使用 Repository 实现。但是,Repository 可以使用 DAO 来访问底层存储。

而且,如果我们有一个贫血域,Repository 将只是一个 DAO。

此外,Repository 模式鼓励域驱动的设计,也为非技术团队成员提供了对数据结构的轻松理解。

  • 职责不同:Repository 负责数据访问的逻辑管理,封装与数据库的交互操作,包括数据的增删改查等。Repository 的设计目标是提供一个统一的接口,将数据访问逻辑与业务逻辑分离,使得业务逻辑更加清晰和可维护。DAO 更关注于数据访问的实现细节,与具体的数据库交互,实现数据的存储和检索等功能。
  • 抽象层次不同:Repository 提供一种更加抽象的数据访问方式,将数据访问的逻辑从业务逻辑中分离出来,使得业务逻辑与数据访问无关,降低代码耦合度,提高可维护性和可扩展性。Repository 定义一组通用的接口和方法,供业务模块调用。DAO 更接近于具体的数据访问实现,直接与数据库交互,实现数据的存储和检索等功能。DAO 的设计目标是提供一组具体的数据访问方法,以满足业务模块的具体需求。

6.结论

在本文中,我们探讨了 DAO 和 Repository 模式之间的差异。

首先,我们研究了 DAO 模式的基本实现。然后,我们看到了使用 Repository 模式的类似实现。

最后,我们研究了一个利用多个 DAO 的 Repository,它增强了域解决业务用例的能力。

因此,我们可以得出结论,当应用程序从以数据为中心转向面向业务时,Repository 模式被证明是一种更好的方法。

🚀 译自《DAO vs Repository Patterns》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/37175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习基准模型Mamba

深度学习基准模型Mamba Mamba(英文直译&#xff1a;眼镜蛇)具有选择性状态空间的线性时间序列建模&#xff0c;是一种先进的状态空间模型 (SSM)&#xff0c;专为高效处理复杂的数据密集型序列而设计。 Mamba是一种深度学习基准模型&#xff0c;专为处理长序列数据而设计&…

【鸿蒙学习笔记】位置设置

官方文档&#xff1a;位置设置 目录标题 align&#xff1a;子元素的对齐方式direction&#xff1a;官方文档没懂&#xff0c;看图理解吧 align&#xff1a;子元素的对齐方式 Stack() {Text(TopStart)}.width(90%).height(50).backgroundColor(0xFFE4C4).align(Alignment.TopS…

<Python><ffmpeg>基于python使用PyQt5构建GUI实例:音频格式转换程序(MP3/aac/wma/flac)(优化版2)

前言 本文是基于python语言使用pyqt5来构建的GUI,功能是使用ffmpeg来对音频文件进行格式转换,如mp3、aac、wma、flac等音乐格式。 UI示例: 环境配置 系统:windows 平台:visual studio code 语言:python 库:pyqt5、ffmpeg 概述 本文是建立在之前的博文的基础上的优化版…

在线教育项目(一):如何防止一个账号多个地方登陆

使用jwt做验证&#xff0c;使用账号作为redis中的key,登录的时候生成token放到redis中&#xff0c;每次申请资源的时候去看token 有没有变&#xff0c;因为token每次登录都会去覆盖&#xff0c;只要第二次登录token就不一样了

Day7:.翻转字符串里的单词 151 卡码网:55.右旋转字符串

题目 151. 反转字符串中的单词 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:// 移除多余空格void moveSpace(string& s) {// 定义快慢指针int slow 0;int fast 0;// 删除前导空格while (s.size() > 0 && fast < s.size() &&…

【算法——双指针前缀和】

例题&#xff1a; 奇偶排序数组&#xff08;与下标对应&#xff09; 奇数偶数个数相等 922. 按奇偶排序数组 II #include<iostream> #include<vector> #include<algorithm> using namespace std;int main() {vector<int>nums { 4,2,5,7 };//指针x…

==和equals的区别(面试题)

和equals有什么区别 对于基本数据类型&#xff0c;比较的是值是否相等&#xff0c;对于引用类型则是比较的地址是否相等&#xff1b;对于equals来说&#xff0c;基本数据类型没有equals方法&#xff0c;对于引用类型equals比较的是引用对象是否相同 那针对以上结论&#xff0c…

西点领导力:卓越是怎样练成的

今天刚看了一个美国西点军校第50任校长&#xff1a;罗伯克卡斯伦的《为什么跟西点军校学领导力培养》这个演讲。从中受益良多&#xff0c;于是我就去了解了一下这位校长以及西点军校。 西点军校 西点军校&#xff08;United States Military Academy, USMA&#xff09;&#…

Android常用加解密算法总结

Android开发中对于数据的传输和保存一定会使用加密技术&#xff0c;加密算法是最普遍的安保手段&#xff0c;多数情况数据加密后在需要使用源数据时需要再进行解密&#xff0c;但凡是都有例外。下面从可逆加密、不可逆、不纯粹加密三种方式记录一下常见的加解密算法。 加密技术…

【使用sudo apt-get出现报错】——无法获得锁 /var/lib/dpkg/lock-open(11:资 源暂时不可用) ,是否有其他进程正占用它?

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、ubuntu中进程正在被占用1. 问题描述2. 原因分析3. 解决 总结 前言 一、ubuntu中进程正在被占用 1. 问题描述 在Ubuntu中&#xff0c;使用终端时输入带有…

昇思25天学习打卡营第7天之二 | 模型保存与加载

1. 保存与加载 在训练网络模型的过程中&#xff0c;实际上我们希望保存中间和最后的结果&#xff0c;用于微调&#xff08;fine-tune&#xff09;和后续的模型推理与部署&#xff0c;本章节我们将介绍如何保存与加载模型。 1.1 导入依赖 # 导入numpy库&#xff0c;并将其重命…

六月,允许自己做自己,别人做别人

今天结束后&#xff0c;2024 就过去一半了。 年初的规划完成一半了吗&#xff1f;如果没有也没关系&#xff0c;做你自己继续前进。 家人来北京旅游&#xff0c;我累趴了 六月初&#xff0c;我搬家了&#xff0c;这次租了一整套房&#xff0c;是一个小俩居、还带一个小阁楼。…

数学学习与研究杂志社《数学学习与研究》杂志社2024年第6期目录

课改前沿 基于核心素养的高中数学课堂教学研究——以“直线与圆、圆与圆的位置关系”为例 张亚红; 2-4 核心素养视角下初中生数学阅读能力的培养策略探究 贾象虎; 5-7 初中数学大单元教学实践策略探索 耿忠义; 8-10《数学学习与研究》投稿&#xff1a;cn7kantougao…

使用Python绘制极坐标图

使用Python绘制极坐标图 极坐标图极坐标图的优点使用场景 效果代码 极坐标图 极坐标图&#xff08;Polar Chart&#xff09;是一种图表类型&#xff0c;用于显示在极坐标系中的数据。极坐标图使用圆形坐标系&#xff0c;角度表示一个变量的值&#xff0c;半径表示另一个变量的…

线程安全问题(二)——死锁

死锁 前言可重入锁逻辑 两个线程两把锁&#xff08;死锁&#xff09;死锁的特点多个线程多把锁&#xff08;哲学家就餐问题&#xff09;总结 前言 在前面的文章中&#xff0c;介绍了锁的基本使用方式——锁 在上一篇文章中&#xff0c;通过synchronized关键字进行加锁操作&am…

XML简介XML 使用教程XML的基本结构XML的使用场景

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

VMware每次打开网络设置都出现需要运行NetworkManager问题

每次打开都出现这个情况&#xff0c;是因为之前把NetworkManager服务服务关闭&#xff0c;重新输入命令&#xff1a; sudo systemctl start NetworkManager.service或者 sudo service network-manager restart 即可解决&#xff0c;但是每次开机重启都要打开就很麻烦&#xf…

【Chapter4】汇编语言及其程序设计,《微机系统》第一版,赵宏伟

一、汇编语言概述 **指令&#xff1a;**指使计算机完成某种操作的命令。 **程序&#xff1a;**完成某种功能的指令序列。 **软件&#xff1a;**各种程序总称。 **机器语言&#xff1a;**计算机能直接识别的语言。用机器语言写出的程序称为机器代码。 **汇编语言&#xff1…

Forecasting from LiDAR via Future Object Detection

Forecasting from LiDAR via Future Object Detection 基础信息 论文&#xff1a;cvpr2022paper https://openaccess.thecvf.com/content/CVPR2022/papers/Peri_Forecasting_From_LiDAR_via_Future_Object_Detection_CVPR_2022_paper.pdfgithub&#xff1a;https://github.co…

SyncUnsafeCell替换Mutex提高性能

1. 背景 在Rust开发过程中&#xff0c;很多情况下需要在不可变的情况下获取可变性或者在多线程的情况下可以安全的贡献可变数据。这种情况下我们一般使用**Mutex来实现通过加锁来实现。现在我们可以通过使用SyncUnsafeCell来替代Mutex**。 2. SyncUnsafeCell SyncUnsafeCell…