DDD架构如何分层?
1 个回答
只有行动才能说明一切。楚风# 一、典型 4 层分层(自上而下) ``` [ Interface / API / UI ] —— 接入层(控制器、RPC 接口、认证/鉴权) [ Application Layer ] —— 应用层(用例编排、事务、权限、发布领域事件) [ Domain Layer ] —— 领域层(实体/值对象/聚合根、领域服务、领域事件) [ Infrastructure Layer ] —— 基础设施层(仓储实现、消息、DB/缓存/外部系统适配) ``` ## 1) Interface / API / UI(接入层) * 内容:Controller、GraphQL/REST/RPC 接口、DTO、参数校验、认证鉴权。 * 只做:入参→DTO→调用 **应用层用例**;出参拼装。 * 不做:**业务规则**、**持久化操作**。 ## 2) Application(应用层) * 内容:应用服务(Use Case)、命令/查询处理器(CQRS)、事务边界、权限检查、跨聚合/跨上下文编排、发布领域事件。 * 只做:**编排**与**协调**(调用领域模型完成业务),控制事务。 * 不做:领域规则(放领域层);SQL/外部访问(通过接口/仓储)。 ## 3) Domain(领域层) * 内容:**实体(Entity)**、**值对象(Value Object)**、**聚合/聚合根(Aggregate/AR)**、**领域服务(Domain Service)**、**领域事件**、工厂、仓储接口。 * 职责:承载 **业务不变量** 与规则;对外暴露行为方法,由聚合根维护内部一致性。 * 依赖:**不依赖技术框架**;仅定义 **Repository 接口**(端口)。 ## 4) Infrastructure(基础设施层) * 内容:Repository 实现(JPA/MyBatis)、消息中间件适配、外部系统客户端、缓存、配置、日志等。 * 职责:为上层提供技术能力实现;把领域的端口对接到具体技术(**适配器**)。 * 依赖:可以依赖任何技术库,但**不能反向让领域层依赖它**。 # 二、依赖方向(箭头只能向下) ``` Interface → Application → Domain → Infrastructure(接口) ↑ ↓ 定义 实现(适配器) ``` * 领域层**只定义接口**(如 `OrderRepository`),实现放在基础设施层(依赖倒置)。 * 应用层调用领域层的模型与仓储接口;基础设施层提供实现并注入(DI)。 # 三、事务边界与一致性 * **一个用例 = 一次应用层服务方法 = 一个事务**(写路径)。 * **聚合 = 事务一致性最小单元**:聚合内强一致;跨聚合用 **领域事件 + 最终一致**(Outbox/重试/幂等)。 * 查询(读路径)可走 **CQRS**:应用层 Query Handler 读专用模型/索引/缓存,不经聚合执行业务规则。 # 四、端口-适配器(六边形思想与 DDD 分层结合) * **端口(Port)**:在领域/应用层定义的抽象接口(如 `OrderRepository`、`PaymentGateway`)。 * **适配器(Adapter)**:在基础设施层实现端口(MySQL、Redis、Kafka、第三方 API)。 * 好处:领域模型独立于技术细节,容易测试与替换实现。 # 五、Java 项目常见包结构示例 ``` com.example.order ├─ interface // 接入层:controller、dto、vo、assembler ├─ application // 应用层:service、command/query handler、facade ├─ domain // 领域层:model(aggregate/entity/value)、domain-service、event、repo接口 └─ infrastructure// 基础设施:repo实现、mapper、client、mq、config ``` * DTO/VO 只在接口层;**领域层避免出现 DTO**。 * Repository 接口在领域层,具体实现放基础设施层。 * 应用层可拥有 **Assembler** 把 DTO ↔ 领域对象转换。 # 六、一次调用的典型路径(写用例) 1. `Controller` 校验入参 → 组装 `CommandDTO` 2. `ApplicationService` 开启事务、鉴权 → 调用 `OrderRepository` 加载聚合根 3. `Order` 聚合根执行业务:`order.pay(...)`,修改内部状态,记录 `DomainEvent` 4. `ApplicationService` 持久化聚合根(通过仓储),发布领域事件(Outbox 或事件总线) 5. 提交事务,返回结果 DTO 读用例(查询)可直接走 `QueryService` 访问读模型(DB 视图/ES/缓存),不经聚合。 # 七、常见误区 * **把 DDD 当目录规范**:没有围绕“不变量”设计聚合,业务规则仍在 Service/SQL 里。 * **应用层写业务规则**:违反职责;规则应落在聚合/值对象/领域服务。 * **Repository 按表设计**:应以“聚合”为粒度;一个仓储对应一个聚合根。 * **事件乱用**:没有契约与幂等等价约束,导致最终一致性失控。 * **聚合过大**:事务膨胀、锁竞争;宁小勿大,通过事件协作。 # 八、落地检查清单 * [ ] 接口层仅做 I/O、鉴权、组装;不含业务规则 * [ ] 应用层是编排 + 事务边界;不含业务规则 * [ ] 领域层承载规则,聚合设计围绕不变量,**通过聚合根修改** * [ ] 仓储接口在领域层,基础设施层提供实现 * [ ] 写用例一个事务;跨聚合最终一致(Outbox + 幂等消费者) * [ ] 读写是否需要 CQRS;查询是否走读模型 * [ ] 端到端/行为测试覆盖主要用例;领域层可单元测试无 DB 依赖 **一句话总结**: DDD 的分层是 **接口 → 应用 → 领域 → 基础设施**。应用层编排用例与事务,领域层承载业务不变量与规则,基础设施实现技术细节(仓储/消息/外部系统),层间依赖单向向下,并通过端口-适配器与领域解耦。发布于 2025-08-12 10:59 •IP属地 广西举报评论收藏
公众号进入网站体验更佳

