Java 中存储库模式和 DAO 之间的区别
今天,我们将了解数据访问对象 (DAO) 和存储库模式。本文还介绍了它们之间的差异。
数据访问对象模式
这种模式是数据持久化的抽象,也被认为更接近底层存储,主要以表为中心。这就是为什么在大多数情况下,数据访问对象 (DAO) 与数据库表相匹配,从而允许最直接的方法从存储中检索和发送数据,同时隐藏丑陋的查询。
存储库模式
存储库模式是从我们的应用程序中检索存储数据的过程,它隐藏了数据存储系统的各个方面。以下是存储库界面,可让我们通过其 username
查找一个 User
。
interface UserRepository {
User findUserByUsername( Username name );
}
这可以基于我们的存储技术进行一个或多个实施,例如 MySQL、Amazon DynamoDB、Web Service、Oracle 或其他。
我们也可以说存储库模式是一种将数据源与应用程序的其余部分隔离开来的设计模式。存储库在数据源(例如 Web 服务和持久模型)和应用程序的其余部分之间进行调解。
以下是存储库模式使用的图形表示。
你理解正确,存储库类似于 Data Access Object (DAO),但它是一种抽象,它隐藏了用于从业务逻辑中检索数据的所有逻辑。
它的行为类似于模型的包装器,负责从持久存储中访问数据。使用存储库的好处是它将我们的东西如何存储的精确细节与使用它的应用程序分开。
这对于测试非常重要,因为我们可以编写总是返回一个用户
但不访问数据库的存根代码。它使我们摆脱了各种问题,让我们可以为我们的应用程序代码编写快速的单元测试,这将不依赖于存储的数据。
Java 中数据访问对象 (DAO) 和存储库模式之间的区别
主要区别在于存储库仅返回调用层可以理解的对象。大多数情况下,存储库由业务层使用,因此它输出业务对象。
另一方面,数据访问对象返回可能/可能不是整个业务对象的数据。这意味着数据不是有效的业务概念。
如果我们的业务对象只是数据结构,那么它可以暗示我们有建模问题。这意味着糟糕的设计,而至少正确封装对象的存储库将更有意义。
如果我们只是加载或保存数据结构,那么很可能我们不需要存储库。对象关系映射(ORM)就足够了。
如果我们必须处理由各种其他对象(聚合)组成的业务对象,并且该特定对象要求其所有部分保持一致(聚合根),存储库模式是最佳解决方案。
这是因为它抽象了完整的持久性信息。我们的应用程序只要求一个产品
,并且存储库将其作为一个整体返回;恢复对象需要多少查询/表并不重要。
请记住,业务对象不是对象关系映射 (ORM) 实体。这可能是从技术的角度来看,但考虑到设计,一个模型是业务的东西,另一个模型是持久性的东西。
大多数时候,没有直接的兼容性。
以下是我们更喜欢使用存储库模式的一些情况:
- 它用于我们有许多繁重查询的系统中。
- 我们使用存储库模式来避免重复查询。
- 它用于数据存储和域(实体)之间。
- 它还用于使用为其创建存储库的实体规范搜索和删除元素。
现在,让我们通过代码实现来了解这种差异。
DAO 和存储库模式实现之间的区别
让我们从数据访问对象模式的实现开始。
数据访问对象模式实现
在这里,我们需要有下面列出的三个类:
- 一个基本的
Employee
域类 EmployeeDAO
接口,为Employee
域提供简单的 CRUD 操作- 实现
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 将其发送到存储系统以进行持久性。
在这里,我们需要以下类:
EmployeeRepository
接口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) 之上的另一层;但是,存储库是实现业务用例的最佳方式。相比之下,数据访问对象看起来很适合访问数据。