广告
您当前的位置: 首页 >  技术 >  编程开发

领域设计战术:解密仓储模式(Repository)与数据访问对象(DAO)的设计区别

作者:CoderWang 时间:2026-07-06 阅读数:2人阅读

在开展面向对象系统设计时,许多开发人员常常将**仓储模式(Repository)**与传统的**数据访问对象(DAO, Data Access Object)**相混淆,认为它们只是对 SQL 调用进行了相似的包装。这种认知上的错觉,往往导致微服务核心领域逻辑外泄,从而使系统重新退化为贫血模型。

事实上,Repository 和 DAO 在系统架构中的定位、面向的主体、以及对数据一致性的控制边界上有着根本性、原则性的差异。

本文将系统拆解 Repository 与 DAO 的架构维度对比、防腐转换拓扑、以及在 Spring Data JPA/MyBatis 混合架构下的工程代码落地。

一、 战术定位对比:面向集合 vs. 面向数据库

我们通过下表拆解两种持久化战术组件在 DDD 架构中的深层次差异:

特征维度数据访问对象 (DAO)仓储模式 (Repository)
面向的主体面向**数据库物理表**。一个 DAO 通常对应一张物理表。面向**业务聚合根 (Aggregate Root)**。一个聚合根仅对应一个 Repository。
架构所处层次基础设施层(Infrastructure)。直接与底层 SQL 驱动挂钩。**接口声明在领域层 (Domain),具体实现注入在基础设施层**(防腐倒置)。
返回的数据实体数据库 DTO / PO 对象(贫血的数据实体)。**纯净的充血领域聚合实体 (Entity / Aggregate Root)**。
业务语义表达面向 CRUD 物理操作。如 insert(), update()面向**内存集合模拟**。如 save(), find()
---

二、 仓储的防腐数据流转拓扑

Repository 在架构中充当了**阻断物理数据结构污染核心领域层的防腐屏障**。其数据流转拓扑如下:

      [ 应用服务层: Application Service ]
                      │
                      ▼ 1. 调用 Repository.save(OrderAggregate)
      [ 领域层接口: OrderRepository (Interface) ]
                      │ (依赖倒置: 实现类在基础设施层)
                      ▼
 ┌────────────────────┼────────────────────┐
 │ [ 基础设施层: RepositoryImpl 实现 ]     │
 │                                         │
 │  1. 接收纯净充血聚合: OrderAggregate    │
 │  2. 翻译器清洗转换 (OrderTranslator)    │
 │     将 OrderAggregate 拆解转换为:       │
 │     - OrderPO (订单主表PO)              │
 │     - OrderItemPO (订单明细表PO)        │
 │  3. 调用底层的 JPA/MyBatis DAO 执行落盘 │
 │     - OrderDAO.insert(orderPo)          │
 │     - ItemDAO.batchInsert(itemPos)      │
 └─────────────────────────────────────────┘
---

三、 代码实战:订单聚合根的仓储实现

以下展示了如何在基础设施层实现领域层声明的 OrderRepository 接口,并完成聚合根到物理 PO 的防腐转换:

1. 领域层:声明仓储接口(Domain Layer)

package com.company.sales.domain.repository;

import com.company.sales.domain.model.SalesOrder;

/**
 * 订单仓储接口:仅面向领域实体,拒绝任何 DB/SQL 依赖
 */
public interface OrderRepository {
    SalesOrder findById(String orderId);
    void save(SalesOrder order);
}

2. 基础设施层:仓储物理实现与 DAO 装配(Infrastructure Layer)

package com.company.sales.infra.repository;

import com.company.sales.domain.model.SalesOrder;
import com.company.sales.domain.repository.OrderRepository;
import com.company.sales.infra.dao.*;
import com.company.sales.infra.po.*;
import org.springframework.stereotype.Repository;
import java.util.*;

@Repository
public class OrderRepositoryImpl implements OrderRepository {

    private final OrderParentDAO orderParentDao; // 底层物理单表 DAO
    private final OrderItemDAO orderItemDao;

    public OrderRepositoryImpl(OrderParentDAO parentDao, OrderItemDAO itemDao) {
        this.orderParentDao = parentDao;
        this.orderItemDao = itemDao;
    }

    @Override
    public SalesOrder findById(String orderId) {
        // 1. 调用底层物理 DAO 分别拉取主表与子表 PO
        OrderParentPO parentPo = orderParentDao.selectById(orderId);
        List<OrderItemPO> itemPos = orderItemDao.selectByOrderId(orderId);
        
        // 2. 通过翻译器,将多张物理表 PO 组装重建为单个完整的充血订单聚合根返回
        return OrderTranslator.toDomain(parentPo, itemPos);
    }

    @Override
    public void save(SalesOrder order) {
        // 1. 将充血聚合拆解为扁平的物理表 PO
        OrderParentPO parentPo = OrderTranslator.toParentPo(order);
        List<OrderItemPO> itemPos = OrderTranslator.toItemPos(order);
        
        // 2. 依次调用底层 DAO 执行物理更新,保护事务一致性
        orderParentDao.saveOrUpdate(parentPo);
        orderItemDao.batchSaveOrUpdate(itemPos);
    }
}
---

四、 总结

将 Repository 与 DAO 彻底分离,是构筑弹性、清洁微服务架构的必经之路。

它通过**基于接口的依赖倒置设计,确保了数据库存储介质(SQL/NoSQL)的更迭不会向核心领域代码渗透,保障了领域逻辑的高度纯净与可测试性**;并**通过面向聚合根的集合装配模式,强行守护了聚合根的事务与业务一致性边界**。掌握这套仓储防腐与底层数据对象转换技术,是主导大中型企业架构升级、防范系统退化为泥潭代码的看家基本功!

本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。

评论交流 (0)

正在加载评论...
头像

CoderWang

当你还撑不起你的梦想时,就要去奋斗。如果缘分安排我们相遇,请不要让她擦肩和过。我们一起奋斗!

微信