Java 中存储库模式和 DAO 之间的区别

Mehvish Ashiq 2024年2月15日
  1. 数据访问对象模式
  2. 存储库模式
  3. Java 中数据访问对象 (DAO) 和存储库模式之间的区别
  4. DAO 和存储库模式实现之间的区别
Java 中存储库模式和 DAO 之间的区别

今天,我们将了解数据访问对象 (DAO) 和存储库模式。本文还介绍了它们之间的差异。

数据访问对象模式

这种模式是数据持久化的抽象,也被认为更接近底层存储,主要以表为中心。这就是为什么在大多数情况下,数据访问对象 (DAO) 与数据库表相匹配,从而允许最直接的方法从存储中检索和发送数据,同时隐藏丑陋的查询。

存储库模式

存储库模式是从我们的应用程序中检索存储数据的过程,它隐藏了数据存储系统的各个方面。以下是存储库界面,可让我们通过其 username 查找一个 User

interface UserRepository {
  User findUserByUsername(Username name);
}

这可以基于我们的存储技术进行一个或多个实施,例如 MySQL、Amazon DynamoDB、Web Service、Oracle 或其他。

我们也可以说存储库模式是一种将数据源与应用程序的其余部分隔离开来的设计模式。存储库在数据源(例如 Web 服务和持久模型)和应用程序的其余部分之间进行调解。

以下是存储库模式使用的图形表示。

java 中 repository 模式和 dao 的区别——repository 可视化

你理解正确,存储库类似于 Data Access Object (DAO),但它是一种抽象,它隐藏了用于从业务逻辑中检索数据的所有逻辑。

它的行为类似于模型的包装器,负责从持久存储中访问数据。使用存储库的好处是它将我们的东西如何存储的精确细节与使用它的应用程序分开。

这对于测试非常重要,因为我们可以编写总是返回一个用户但不访问数据库的存根代码。它使我们摆脱了各种问题,让我们可以为我们的应用程序代码编写快速的单元测试,这将不依赖于存储的数据。

Java 中数据访问对象 (DAO) 和存储库模式之间的区别

主要区别在于存储库仅返回调用层可以理解的对象。大多数情况下,存储库由业务层使用,因此它输出业务对象。

另一方面,数据访问对象返回可能/可能不是整个业务对象的数据。这意味着数据不是有效的业务概念。

如果我们的业务对象只是数据结构,那么它可以暗示我们有建模问题。这意味着糟糕的设计,而至少正确封装对象的存储库将更有意义。

如果我们只是加载或保存数据结构,那么很可能我们不需要存储库。对象关系映射(ORM)就足够了。

如果我们必须处理由各种其他对象(聚合)组成的业务对象,并且该特定对象要求其所有部分保持一致(聚合根),存储库模式是最佳解决方案。

这是因为它抽象了完整的持久性信息。我们的应用程序只要求一个产品,并且存储库将其作为一个整体返回;恢复对象需要多少查询/表并不重要。

请记住,业务对象不是对象关系映射 (ORM) 实体。这可能是从技术的角度来看,但考虑到设计,一个模型是业务的东西,另一个模型是持久性的东西。

大多数时候,没有直接的兼容性。

以下是我们更喜欢使用存储库模式的一些情况:

  • 它用于我们有许多繁重查询的系统中。
  • 我们使用存储库模式来避免重复查询。
  • 它用于数据存储和域(实体)之间。
  • 它还用于使用为其创建存储库的实体规范搜索和删除元素。

现在,让我们通过代码实现来了解这种差异。

DAO 和存储库模式实现之间的区别

让我们从数据访问对象模式的实现开始。

数据访问对象模式实现

在这里,我们需要有下面列出的三个类:

  1. 一个基本的 Employee 域类
  2. EmployeeDAO 接口,为 Employee 域提供简单的 CRUD 操作
  3. 实现 EmployeeDAO 接口的 EmployeeDAOImplementation

示例代码(员工类):

public class Employee {
  private Long id;
  private String employeeCode;
  private String firstName;
  private String email;

  // write your getters/setters
}

示例代码(EmployeeDAO 接口):

public interface EmployeeDAO {
  void create(Employee employee);
  Employee read(Long id);
  void update(Employee employee);
  void delete(String employeeCode);
}

示例代码(EmployeeDAOImplementation 类):

public class EmployeeDAOImplementation implements EmployeeDAO {
  private final EntityManager entityManager;

  @Override
  public void create(Employee employee) {
    entityManager.persist(employee);
  }

  @Override
  public Employee read(long id) {
    return entityManager.find(Employee.class, id);
  }

  // ... continue with remaining code
}

我们正在使用 JPA EntityManager Interface 与底层存储进行通信。此外,为 Employee 域提供数据访问机制。

存储库模式实现

该模式封装了存储、搜索行为和检索,模拟了对象的集合。与 DAO 一样,它也隐藏查询和处理数据,但位于更接近应用程序业务逻辑的更高级别。

存储库也可以使用 DAO 从数据库中获取数据。此外,它可以填充域对象或从域准备数据,然后使用 DAO 将其发送到存储系统以进行持久性。

在这里,我们需要以下类:

  1. EmployeeRepository 接口
  2. EmployeeRepositoryImplementation

示例代码(EmployeeRepository 接口):

public interface EmployeeRepository {
  Employee get(Long id);
  void add(Employee employee);
  void update(Employee employee);
  void remove(Employee employee);
}

示例代码(EmployeeRepositoryImplementation 类):

public class EmployeeRepositoryImplementation implements EmployeeRepository {
  private EmployeeDAOImplementation employeeDAOImplementation;

  @Override
  public Employee get(Long id) {
    Employee employee = employeeDAOImplementation.read(id);
    return employee;
  }

  @Override
  public void add(Employee employee) {
    employeeDAOImplementation.create(employee);
  }

  // ... continue with remaining code
}

在这里,我们使用 EmployeeDAOImplementation 从数据库中检索/发送数据。所以,我们可以说存储库的实现和 DAO 看起来很相似。

这是因为 Employee 类是贫血领域,而存储库只是数据访问层 (DAO) 之上的另一层;但是,存储库是实现业务用例的最佳方式。相比之下,数据访问对象看起来很适合访问数据。

作者: Mehvish Ashiq
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook