mcpField
D
ddd-domain-service

ddd-domain-service

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

关于 ddd-domain-service

用于判断领域行为何时应由无状态领域服务承担,而非实体或其他层。它区分领域操作、应用层编排与基础设施工作。

主要功能

  1. 01领域服务的适用条件
  2. 02区分三种服务层
  3. 03领域操作命名建议
  4. 04状态与职责范围判断
  5. 05常见服务反模式

适用场景

  1. 01协调跨聚合操作
  2. 02承载无自然实体归属的计算
  3. 03区分用例编排与领域逻辑

安装

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

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

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

详细介绍

一句话概述

领域服务是领域层中的无状态操作,无法自然地归属于某个单独的实体或值对象——通常是因为它需要协调多个聚合,或涉及不以某个对象为核心的领域计算。

何时使用此技能

  • 一个内聚的领域操作涉及多个聚合(例如,在两个 Account 聚合之间转账)。
  • 某项计算涉及领域类型,但不适合作为其中任何一个类型的方法(例如,已知汇率时进行货币兑换)。
  • 将行为强行放到某个参与实体上,会导致该实体对其他实体“了解过多”。

何时不使用此技能

  • 逻辑可以清晰地归属于单个实体——将其放在那里。
  • 工作属于应用层编排(处理用例、开启事务、调用存储库)——这是应用服务,而非领域服务。
  • 工作属于基础设施(HTTP 调用、数据库访问、发送消息)——这是基础设施服务。

核心内容

DDD 代码库中通常会共存三种服务。请将它们区分开来:

领域服务。 位于领域层。只操作领域类型。无状态。用通用语言中的动词来表达——TransferService.transfer(fromAccount, toAccount, amount),而不是 AccountUtils.handleTransfer(...)。

应用服务。 编排用例。开启事务、调用存储库、调用领域服务、分发事件。无状态。位于应用层。

基础设施服务。 与外部世界交互——发送 HTTP 请求、写入数据库、向队列发布消息。位于基础设施层。

领域服务应根据其在领域中的作用命名。TransferService 和 ExchangeRateConverter 是不错的名称。TransferManager 和 TransferHelper 则是不良信号——它们用技术性噪声掩盖了动词。

判断准则

  • 优先采用实体行为。只有当操作涉及多个聚合或没有自然归属时,才考虑使用领域服务。
  • 如果领域服务有状态,它几乎肯定被错误归类了——应将其改为领域实体、值对象,或把状态移入某个参与聚合。
  • 如果领域服务扩展到几十个方法,它很可能是伪装的“事务脚本”——拆分它,或将行为放回实体中。

反模式

  • 每个类都添加 *Service 后缀——领域会变成一组针对数据 DTO 的事务脚本(参见 ddd-anti-patterns 中的贫血领域模型)。
  • 在领域服务中放入基础设施(数据库、HTTP)——这会使领域与部署问题耦合。
  • 领域服务不通过实体的方法就直接修改传入的实体——这会绕过不变量。
  • 持有缓存、会话或其他进程状态的有状态“服务”。

另请参阅

  • ddd-entity — 应优先将行为放在这里。
  • ddd-aggregate — 领域服务通常会跨聚合进行协调。
  • ddd-anti-patterns — 贫血模型和服务膨胀的不良信号。

参考资料

  • Evans,Domain-Driven Design(2003),第 5 章(以软件表达的模型)。

评论

支持 Markdown