【Spring】DAO 和 Repository 的区别

news2025/1/19 7:14:44

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;
    
    @Override
    public void create(User user) {
        entityManager.persist(user);
    }
 
    @Override
    public 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;
    
    @Override
    public User get(Long id) {
        User user = userDaoImpl.read(id);
        return user;
    }
 
    @Override
    public 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 {
    @Override
    public List<Tweet> fetchTweets(String email) {
        List<Tweet> tweets = new ArrayList<Tweet>();
        
        //call Twitter API and prepare Tweet object
        
        return 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;
    
    @Override
    public 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.coloradmin.cn/o/1881104.html

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

相关文章

以太网交换机原理

没有配置&#xff0c;比较枯燥&#xff0c;二可以认识线缆&#xff0c; 三比较重要&#xff0c;慢慢理解&#xff0c;事半功倍。 各位老少爷们&#xff0c;在下给大家说段以太网交换机原理&#xff0c;说得不好大家多多包涵&#xff0c;说得好呢&#xff0c;大家叫个好&#x…

【每日一练】python运算符

1. 算术运算符 编写一个Python程序&#xff0c;要求用户输入两个数&#xff0c;并执行以下运算&#xff1a;加法、减法、乘法、求余、除法、以及第一个数的第二个数次方。将结果打印出来。 a input("请输入第一个数&#xff1a;") b input("请输入第二个数&…

诊断知识:UnconfirmedDTCLimit的使用

文章目录 前言UnconfirmedDTCLimit的含义UnconfirmedDTCLimit的使用UnconfirmedDTCLimit和Failed limit相等UnconfirmedDTCLimit小于Failed limit 总结 前言 在某OEM基础技术规范中&#xff0c;诊断需求经常会出现UnconfirmedDTCLimit这个词汇&#xff0c;但基础技术规范中并没…

菲尔兹奖得主测试GPT-4o,经典过河难题未能破解!最强Claude 3.5回答离谱!

目录 01 大言模型能否解决「狼-山羊-卷心菜」经典过河难题&#xff1f; 02 加大难度&#xff1a;100只鸡、1000只鸡如何&#xff1f; 01 大言模型能否解决「狼-山羊-卷心菜」经典过河难题&#xff1f; 最近&#xff0c;菲尔兹奖得主Timothy Gowers分享了他测试GPT-4o的经历&a…

入门JavaWeb之 JDBC 连接数据库

JDBC&#xff1a;Java Database Connectivity&#xff0c;Java 数据库连接 需要 jar 包支持&#xff1a; java.sql javax.sql mysql-connector-java&#xff08;连接驱动&#xff0c;必须导入&#xff09; 在 MySQL 先建个 jdbc 数据库后 USE jdbc; 执行后再 CREATE TABLE…

DIY智能小车:基于STM32的蓝牙遥控实战教程(附代码)

摘要: 本文将带你从零开始&#xff0c;使用STM32单片机打造一辆炫酷的蓝牙遥控小车。文章将详细讲解硬件选型、电路连接、软件设计以及代码实现&#xff0c;并提供丰富的Mermaid图表和代码示例&#xff0c;助你轻松完成自己的遥控小车项目。 关键词: STM32, 蓝牙遥控, 遥控小车…

苹果笔记本能玩网页游戏吗 苹果电脑玩steam游戏怎么样 苹果手机可以玩游戏吗 mac电脑安装windows

苹果笔记本有着优雅的机身、强大的性能&#xff0c;每次更新迭代都备受用户青睐。但是&#xff0c;当需要使用苹果笔记本进行游戏时&#xff0c;很多人会有疑问&#xff1a;苹果笔记本能玩网页游戏吗&#xff1f;苹果笔记本适合打游戏吗&#xff1f;本文将讨论这两个话题&#…

携手亚马逊云科技,维塑科技推出运动健康领域首个AI大模型

导读&#xff1a;生成式AI运动健康&#xff0c;将如何改变我们的生活&#xff1f; 人工智能技术正不断重塑着我们的工作、生活方式。那么&#xff0c;AI能否改善我们的健康状况呢&#xff1f;AI大模型在运动健康领域的探索为我们带来新的想象。 2023年&#xff0c;全球领先的AI…

Android常用加解密算法总结

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

线程的调度

线程的执行总是趋向于CPU受限或IO受限 一些线程需要花费一定的时间使用CPU进行计算&#xff0c;而另外一些线程则会花费一些时间等待相对较慢的I/O操作的完成 一个用于计算16位整数的14次方根的线程属于前者&#xff0c;而一个等待人类用户通过敲击键盘提供输入数据的线程则属…

Bytebase 2.20.0 - 支持为工单事件配置飞书个人通知

&#x1f680; 新功能 支持 Databricks。支持 SQL Server 的 TLS/SSL 连接。支持为工单事件配置飞书个人通知。支持限制用户注册的邮箱域名。 &#x1f514; 重大变更 将分类分级同步设置从数据库配置移至工作空间的全局配置。 SQL 编辑器只读模式下只允许执行 Redis 的只读…

Java SE入门及基础(60) 线程的实现(下) 线程的同步(synchronized 和 Lock 的实现) 线程通信 线程状态

目录 线程 &#xff08;下&#xff09; 4. 线程同步-synchronized 同步方法语法 示例 同步代码块语法 示例 synchronized锁实现原理 5. 线程同步-Lock 示例 6. 线程通信 Object类中的通信方法 案例 分析 代码实现 7. 线程状态 线程状态转换图 线程 &#xff08…

老师如何将期末成绩单独发给家长?

老师们&#xff0c;期末季又到了&#xff0c;又要面临一个重要而微妙的任务——发放期末成绩。在这个信息爆炸的时代&#xff0c;如何安全、高效、又充满人情味地将成绩单送到家长手中&#xff0c;成了我们的一项挑战。今天&#xff0c;我就来和大家分享一些小技巧&#xff0c;…

Wp-scan一键扫描wordpress网页(KALI工具系列三十二)

目录 1、KALI LINUX 简介 2、Wp-scan工具简介 3、信息收集 3.1 目标IP&#xff08;服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描已知漏洞 4.3 扫描目标主题 4.4 列出用户 4.5 输出扫描文件 4.6 输出详细结果 5、总结 1、KALI LINUX 简介 Kali Linux 是一…

LeetCode 算法:二叉树的右视图 c++

原题链接&#x1f517;&#xff1a;二叉树的右视图 难度&#xff1a;中等⭐️⭐️ 题目 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4…

某易六月实习笔试

第一题 下面代码需要更改的地方已指出。 解题思路 模拟题&#xff0c;用双指针记录双方当前式神&#xff0c;再记录一下当前谁先手&#xff0c;直到有一方指针越界。 把下面代码now1变为now(now1)%2就行。 第二题 解题思路 01背包变种&#xff0c;只是背包的容量变为多个维度…

清华大学世界排名:2025QS世界大学排名第20名

近日&#xff0c;国际高等教育研究机构QS Quacquarelli Symonds正式发布了2025QS世界大学排名&#xff0c;其中麻省理工学院连续第13年蝉联榜首&#xff0c;北京大学排名由去年的全球第17上升至全球第14名&#xff0c;清华大学位列2025QS世界大学排名第20名&#xff0c;以下是查…

【高级篇】分区与分片:MySQL的高级数据管理技术(十三)

引言 在上一章,我们探讨了MySQL的主从复制与高可用性,这是构建健壮数据库架构的基石。现在,让我们深入到更高级的主题——分区与分片,这些技术对于处理大规模数据集和提升数据库性能至关重要。我们将详细介绍表分区的概念、类型及分片技术的应用,为下一章讨论MySQL集群与…

【硬件视界2】CPU和GPU:计算机架构的双子星

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 本篇笔记整理&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、CPU (中央处理器)①主要作用②特点 2、 GPU (图形处理…

架构师篇-9、从事件风暴到微服务设计的落地过程

用户付款功能第二个版本的设计实现 单一职责原则&#xff08;SRP&#xff09; 软件系统中的每个元素只完成自己职责内的事&#xff0c;将其他的事交给别人去做“职责”通常人理解为一个事情&#xff0c;与该事情相关的事都是它的责任 一个职责是软件变化的一个原因 第二次需求…