分层与依赖倒置
用途:决定代码放哪一层、依赖方向怎么约束时查阅
定义
「定义」小节链接DDD 的经典分层是四层,依赖只能指向领域层:
接口层(interfaces / adapter) 协议转换、参数绑定、结果装配 ↓应用层(application) 用例编排、事务边界、权限与幂等 ↓领域层(domain) 聚合、值对象、领域事件、领域服务、仓储接口 ↑ 实现基础设施层(infrastructure) ORM、SQL、消息、外部系统客户端、仓储实现依赖倒置是关键:领域层定义仓储与外部能力的接口,基础设施层提供实现。于是“领域层不认识数据库”成为可验证的事实,而不是口号。
由来与要解决的问题
「由来与要解决的问题」小节链接三层结构(UI/Service/DAO)只解决了代码归类,没有解决“业务规则与基础设施互相渗透”。当 Service 同时依赖 HTTP 客户端、SQL 映射与业务判断时,规则无法独立测试,换技术栈等于改业务。
四层 + 依赖倒置把“业务语义”变成最内层、最稳定的部分,外围都是可替换的适配。
包与模块组织
「包与模块组织」小节链接domain/ order/ Order(聚合根), OrderLine, OrderStatus, OrderRepository(接口) pricing/ PricePolicy, DiscountSpecificationapplication/ order/ PayOrderService, ShipOrderService, OrderEventPublisher(接口)infrastructure/ persistence/ OrderRepositoryImpl, OrderPO, OrderAssembler messaging/ RocketMQOrderEventPublisher external/ RiskControlClientAdapterinterfaces/ web/ OrderController, 请求/响应模型 job/ mq/ 定时任务与消息入口,复用同一批应用服务要点:入口不止 HTTP。同一用例必须能被定时任务、消息消费者复用,因此编排逻辑不能留在 Controller。
模型流转与转换
「模型流转与转换」小节链接| 模型 | 用途 | 转换发生地 |
|---|---|---|
| 请求/响应模型 | 对外协议 | 接口层 |
| 领域模型 | 业务规则 | 领域层 |
| 持久化对象(PO) | 表结构 | 基础设施层 |
| 投影/视图模型 | 查询展示 | 查询服务 |
转换次数多确实带来样板成本,但它换来的是“改表不动模型、改协议不动业务”。Assembler/映射器(MapStruct 类工具)负责这部分机械代码。
约束如何固化
「约束如何固化」小节链接口头约定必然退化,需要机器检查:
- 架构测试:断言
domain包不依赖infrastructure、不 import ORM/HTTP 包(ArchUnit、Dependency-Cruiser 类工具)。 - 构建期校验:把架构测试接入 CI,违反即失败。
- 模块边界:多上下文时用 Maven/Gradle 模块强制可见性,比包约定更硬。
与其他概念的关系
「与其他概念的关系」小节链接- 六边形/洋葱/整洁架构:同一思想的变体,差别在端口与适配器的显式程度(见分层架构演进相关词条)。
- COLA:把四层与扩展点固化为骨架模板。
- 资源库:依赖倒置的最常见落点。
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
领域层加 Spring/ORM 注解(@Table、@Entity 混用) |
至少保证领域模型不携带表结构与 SQL 语义 |
| 四层变成“每层都写一遍” | 简单模块可用简化结构,按子域价值分级投入 |
| 应用层直接操作 PO | 通过仓储与聚合,PO 不出基础设施层 |
| 只分层不分上下文 | 层内仍是大泥球,跨模块随意调用 |
| 目录很深但依赖方向没约束 | 加架构测试,让违规在 CI 失败 |
延伸阅读
「延伸阅读」小节链接- Eric Evans《领域驱动设计》第 13 章(架构分层)
- Vaughn Vernon《实现领域驱动设计》第 11 章
- Robert C. Martin《Clean Architecture》(依赖规则章节)