领域服务与应用服务
领域服务承载跨多个聚合或多个实体才能完成的领域规则,自身无状态,属于领域层;应用服务负责编排用例:加载聚合、调用领域逻辑、提交事务、发布事件并做权限校验,属于应用层。二者都是无状态的,区别在于关注点是业务规则还是流程编排。业务规则写进应用服务会导致多处重复,应用流程写进领域层会让模型依赖框架与事务设施。
对比
| 维度 | 领域服务 | 应用服务 |
|---|---|---|
| 关注点 | 业务规则与不变量 | 用例编排与事务边界 |
| 状态 | 无状态 | 无状态 |
| 依赖 | 领域模型与领域接口 | 仓储、领域服务、消息、鉴权 |
| 示例 | 跨账户转账手续费计算 | 提交订单用例的流程编排 |
| 测试 | 纯业务输入输出,易做单元测试 | 需要替身模拟仓储与消息 |
划分判断
- 规则需要跨多个聚合或实体才能计算完整,考虑放入领域服务
- 逻辑主要是“取数据、调用、保存、发事件”的顺序编排,属于应用服务
- 规则只涉及单个聚合内部,直接写进聚合,不需要额外服务
- 逻辑与技术设施强相关(事务、消息、鉴权),不要放进领域层
- 同一规则在多个用例中重复出现,抽到领域服务或聚合中
- 只有一次调用且无复用价值的流程,保持扁平,不要为对称而分层
基本信息
| 命名习惯 | 领域服务用业务动作命名,应用服务以用例名称命名 |
|---|---|
| 事务边界 | 通常由应用服务控制,聚合内部负责不变量 |
| 常见误区 | 把领域服务当工具类,塞入与业务无关的通用方法 |
| 与事务脚本区别 | 事务脚本把规则与流程混在一起,难以复用与测试 |
| 落地收益 | 规则集中后修改点唯一,重复实现的风险显著下降 |
如果领域服务只有一层转发、方法体只是调用仓储,通常说明它没有存在的必要,直接在应用服务里完成即可。
应用服务里堆积大量业务判断,是贫血模型的典型信号:规则散落、无法复用,同一规则在不同用例中实现不一致。