mcpField
D
ddd-repository

ddd-repository

github.com/yonatankarp开发144 次安装23 周前更新
代码仓库

关于 ddd-repository

用于指导领域驱动设计中的 Repository。帮助开发者围绕完整聚合根定义领域语言操作,并将持久化细节隔离在领域层之外。

主要功能

  1. 01每个聚合根对应一个 Repository
  2. 02接口位于领域层
  3. 03实现在基础设施层
  4. 04使用领域语言命名查询
  5. 05说明读模型的边界

适用场景

  1. 01按标识加载或保存聚合
  2. 02替换暴露持久化类型的 DAO
  3. 03将展示查询移至读模型

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yonatankarp/software-design-skills --skill ddd-repository

安装后在 Claude Code 中输入/ddd-repository确认已加载。

详细介绍

一句话摘要

仓库将持久化隐藏在内存聚合集合的表象之下——领域代码无需知道存储使用的是 SQL、键值存储还是内存。

何时使用此技能

  • 按标识加载或保存聚合。
  • 替换那些将持久化类型泄漏到领域层的临时 DAO。
  • 定义一小组具有领域意义的查询(findActiveByCustomer,而非 findByStatusEqualsAndCustomerIdEquals)。

何时不使用此技能

  • 值对象——它们没有可用于查找的标识。
  • 用于展示的跨聚合查询——应构建读取模型,而不是仓库方法。
  • 报表 / 分析——这类需求需要针对读取优化的查询层,而不是领域仓库。

核心内容

仓库服务于一个聚合根。其接口位于领域层;其实现位于基础设施层。领域代码只依赖接口;基础设施代码负责接入实现。

接口使用通用语言。方法名称应描述业务要做什么,而不是持久化机制。findActiveByCustomer 是合适的。findByStatusEqualsAndCustomerIdEquals 则是披着领域外衣的 SQL 查询名称——抽象已经泄漏。

仓库处理的是完整聚合。它不会返回半个聚合、聚合内部的实体或数据库行。返回的是聚合根;调用方通过它进行操作。

如果查询用于展示——向用户显示订单列表、汇总客户活动、构建仪表板——通常就不属于仓库。应构建独立的读取模型,并提供自己的查询接口,针对视图进行优化。

决策启发

  • 每个聚合根对应一个仓库,而不是每个实体对应一个仓库。
  • 如果方法暴露了持久化类型(JPA 语境中的 Query、Predicate、Specification、EntityManager),说明抽象已经泄漏——应将这些类型下沉到更底层。
  • 如果方法返回行、DTO 或部分实体,就不是领域仓库操作。应将它移到读取模型中。
  • 如果仓库的方法超过约 5–8 个,应考虑其中是否有些其实是伪装成仓库方法的读取模型查询。

反模式

  • 仓库返回行、DTO 或持久化类型。
  • 每个实体各有一个仓库,从而暴露聚合内部结构。
  • 使用随意的查找方法(findByXAndYAndZAndW),而不是一小组命名清晰且具有领域意义的方法。
  • 将框架的通用 JpaRepository / CrudRepository 直接用作领域仓库——这会不加区分地暴露所有 CRUD 操作,并使领域层依赖 JPA。

另请参阅

  • ddd-aggregate——仓库操作的对象。
  • ddd-factory——用于创建聚合;仓库负责处理其持久化生命周期。
  • ddd-anti-patterns——会泄漏实现细节的仓库和以 CRUD 命名的方法。

参考资料

  • Evans,《领域驱动设计》(2003),第 6 章(领域对象的生命周期)。

评论

支持 Markdown