领域驱动设计 (DDD) 架构完全解析

什么是 DDD (Domain-Driven Design)?

DDD 并不是一种框架(像 Spring Boot),也不是一种具体的技术(像 MySQL、ES),它是一种软件架构设计思想复杂业务系统的破局方法论

它的核心理念是:"软件设计的核心在于深刻理解和抽象真实的业务领域,让代码结构与现实业务逻辑保持高度一致。"

简单来说:以前我们写代码,是"面向数据库编程"(先建表,再写增删改查);而在 DDD 中,我们是"面向业务模型编程"(先理清业务概念,再考虑怎么存)。


为什么需要 DDD?(痛点与破局)

痛点:传统的"面条代码"与"大泥球"

在传统的 MVC 架构(Controller -> Service -> Dao -> 数据库表)中,当业务变得极其复杂时(比如全房通这种涉及租赁、财务、审批、维修的庞大系统):

  1. Service 层变得无限臃肿 :一个 HousingService.java 可能有几千行代码,里面塞满了业务校验、计算账单、发消息、调其他接口的逻辑。

  2. 贫血模型 (Anemic Domain Model) :我们写的 Housing 实体类(Entity)只有几十个 getset 方法,它本身没有任何业务逻辑。所有的逻辑都在 Service 里,实体成了一个单纯的"数据袋"。

  3. 牵一发而动全身:改了一个财务计算的 Bug,结果导致收房功能挂了。因为代码高度耦合。

DDD 的破局之道

DDD 将庞大的系统拆分成多个独立的**"界限上下文 (Bounded Context)"**,也就是微服务的雏形。比如:

  • 租赁域(管收房、出房、合同)

  • 财务域(管账单、流水、催收)

  • 基础域(管店面、员工、字典)

在每个域内,构建自己独立的充血模型(有状态、有行为的实体),各管各的事。


DDD 的四大核心概念 (以全房通系统为例)

1. 实体 (Entity) 与 值对象 (Value Object)

  • 实体 (Entity):有唯一标识,且状态会随时间变化的业务对象。

    • 例子qft_housing(房源)。一套房子从"未审核"变成"已租",它的状态在变,但它的房源编号(如 ZB0288)永远不变,它是实体。
  • 值对象 (Value Object):没有唯一标识,只用来描述事物特征的对象。

    • 例子:房子的"面积 (98㎡)"、"户型 (3室1厅)"。如果把 3室1厅 改成 2室1厅,它其实变成了一个全新的户型描述,这类属性通常作为值对象依附在实体上。

2. 聚合 (Aggregate) 与 聚合根 (Aggregate Root)

这是 DDD 最重要的概念。

  • 聚合:一组生命周期强绑定、需要保证数据一致性的实体和值对象的集合。

  • 聚合根:这个集合的"带头大哥"。外界想操作集合里的任何东西,都必须通过聚合根。

    • 例子qft_housing(房源)是聚合根qft_housing_cover_other_expenses(代扣附加费)是集合内的子实体。

    • 规则 :你不能跳过房源直接去给附加费表插一条数据;你必须调用房源聚合根的 addExpense() 方法,由房源自己去校验(比如:房源是不是被冻结了?)并最终落盘。

3. 领域服务 (Domain Service)

当一个业务逻辑跨越了多个聚合根,不适合放在任何一个单一的实体里时,就用领域服务。

  • 例子 :转租业务。涉及把 A 房源的租客退掉,并在 B 房源重新生成合同。这不属于 A 房源,也不属于 B 房源,这是一个跨聚合的 TransferHousingDomainService

4. 领域事件 (Domain Event)

当聚合根的状态发生重大改变时,向外发出的广播(通常借助 RabbitMQ / Kafka)。

  • 例子 :房源登记成功后,发出一个 HousingRegisteredEvent 事件。

  • 效果:财务域监听到这个事件,去生成账单;搜索域监听到,去更新 ES 索引。这就实现了模块间的彻底解耦。


DDD 典型的四层架构代码结构

如果全房通的后端严格按照 DDD 重构,它的代码目录大概长这样:

复制代码
com.qft.lease (租赁域)
├── api (用户接口层)
│   └── controller (接收 HTTP 请求,转交给应用层)
│
├── application (应用层)
│   └── service (负责编排调度,不写核心业务逻辑。如:开启事务 -> 调用领域模型 -> 发送 MQ 消息)
│
├── domain (领域层 - 核心!)
│   ├── model
│   │   ├── Housing (房源聚合根实体,里面写满了校验和状态流转的业务逻辑)
│   │   └── Expense (附加费实体)
│   ├── repository (只定义接口:HousingRepository,不写实现)
│   └── event (领域事件定义)
│
└── infrastructure (基础设施层)
    ├── persistence (这里才写 MyBatis/JPA,实现领域层的 Repository 接口,存入 MySQL)
    ├── mq (RabbitMQ 的发送实现)
    └── search (ES 的查询实现)

总结:DDD 带来的改变

  1. 代码即业务 :非技术人员看 Domain 层的代码(如 housing.checkOut()),就能看懂业务逻辑,不再是一堆干瘪的 setStatus(1)

  2. 保护核心资产 :无论外围的数据库从 MySQL 换成 Oracle,还是消息队列从 RabbitMQ 换成 Kafka(基础设施层变化),最核心的领域层(Domain)代码一行都不用改

  3. 完美契合微服务:按 DDD 的界限上下文拆分微服务,边界最清晰,不会出现服务间数据库乱连、逻辑乱调的"分布式大泥球"。

相关推荐
沐风清扬2 小时前
复杂业务系统架构:CQRS 读写分离与 ES/RabbitMQ 基础指南
微服务·架构
ai产品老杨4 小时前
GB28181与RTSP全协议兼容之道:基于Docker与微服务架构的AI视频中台架构解析(附源码交付方案)
docker·微服务·架构
SamDeepThinking16 小时前
中小团队需要一个资源微服务
后端·微服务·架构
不才小强18 小时前
gRPC实战指南:高性能微服务通信框架
微服务·云原生·架构
迷藏4941 天前
# 发散创新:用Locust实现高并发场景下的精准压力测试与性能调优实战在现代微服务架构中,**接口稳定性与响应速度**已成为衡量
java·python·微服务·架构·压力测试
掘根1 天前
【微服务即时通讯】客户端数据中心
qt·微服务·架构
面汤放盐1 天前
架构对比:单体架构与微服务架构
微服务·云原生·架构
iwS2o90XT1 天前
微服务架构设计:Spring Cloud Gateway与Nacos集成
微服务·云原生·架构
喜欢流萤吖~1 天前
分布式事务:微服务的数据一致性之困
分布式·微服务·架构