DDD:领域驱动设计的初步认识
DDD(领域驱动设计)一直是 Java 后端中讨论度很高的话题。有人觉得它是复杂系统的救星,也有人觉得它过度设计。在真正学习 DDD 的各种概念之前,更重要的问题其实是:DDD 到底解决了什么问题?
目录
传统架构的痛点
做 Java 后端开发的同学对三层架构一定不陌生:Controller 接收请求,Service 处理业务逻辑,DAO 操作数据库。这个分层方式清晰直观,上手也快,很多项目一开始都是这么搭的。
但随着业务越来越复杂,真正的问题不是 Controller、Service、DAO 三层不够,而是业务规则越来越分散。
创建订单能不能取消?什么时候允许退款?库存什么时候扣减?积分什么时候发放?这些规则到底应该写在哪里?有人写在 Controller,有人写在 Service,还有人放进各种 Util 或 Manager 中。时间一长,同一个业务被拆散到多个地方,维护越来越困难。
根本原因在于:传统三层架构按技术职责组织代码,而不是按业务能力组织代码。
Controller 负责接收请求,Service 负责业务处理,DAO 负责数据访问。随着业务越来越复杂,一个业务会同时分散到多个技术层中,业务本身的边界反而越来越模糊。
DDD 是什么
DDD,全称 Domain-Driven Design,领域驱动设计。2003 年 Eric Evans 在同名书中提出。
让代码的结构反映业务的结构,而不是数据库表的结构。 换句话说,就是先思考业务,再思考技术。
传统架构下,代码的组织方式是按技术分层的:Controller 层、Service 层、DAO 层。每个层关心的是技术职责,不是业务职责。而 DDD 的思路是反过来:先搞清楚业务领域是怎么划分的,再按业务领域来组织代码。
举个例子。一个电商系统,按传统架构分层是这样的:
controller/
OrderController.java
UserController.java
ProductController.java
service/
OrderService.java
UserService.java
ProductService.java
dao/
OrderDao.java
UserDao.java
ProductDao.java
按 DDD 的思路组织是这样的:
order/
Order.java
OrderService.java
...
user/
User.java
UserService.java
...
product/
Product.java
ProductService.java
...
在传统架构下,一个订单相关的逻辑散落在 Controller、Service、DAO 三个目录里。DDD 下,订单相关的所有东西都在 order 包里。修改订单相关功能时,大部分代码都会集中在 order 模块,而不是在 Controller、Service、DAO 三层之间来回切换。
DDD 和传统架构的区别
两种架构的核心差异可以从几个维度来看:
| 维度 | 传统架构 | DDD |
|---|---|---|
| 设计中心 | 数据库表 | 领域模型 |
| 代码组织 | 按技术分层(Controller/Service/DAO) | 按业务领域划分(order/user/product) |
| 业务逻辑归属 | 散落在各层 | 内聚到领域对象中 |
| Entity 对象 | 数据载体(贫血模型) | 封装数据和业务行为(充血模型) |
| 数据库依赖 | Service 直接依赖 DAO | 通过 Repository 接口隔离 |
| 新增功能 | 可能要改三个层 | 只改对应的领域模块 |
传统架构下,Service 层是业务逻辑的主要承载者,但 Service 本身是一个"什么都能往里放"的容器。一个 OrderService 可能同时负责订单创建、订单查询、订单取消、订单退款、订单状态流转......职责越来越多,代码越来越长。
DDD 做的事情是把业务逻辑下沉到领域对象里。Order 实体不只是一个数据容器,它维护自己的业务规则,例如哪些状态允许取消、哪些订单允许退款、状态如何流转等。Service 层变成一个协调者,负责编排领域对象完成业务流程,而不是把所有逻辑都扛在自己身上。
打个比方。传统架构更像是把所有 Java 文件按"类型"放到不同文件夹:Controller、Service、DAO。DDD 更像是按"业务模块"整理代码:订单相关放一起、用户相关放一起、商品相关放一起。找订单代码时,不需要在多个目录之间来回切换。
什么时候该用 DDD
没有万金油的技术,DDD同样需要结合项目实际情况去判断是否需要使用。
适合 DDD 的场景:
- 业务规则复杂、多变。比如电商系统的订单状态流转、金融系统的风控规则、ERP 系统的业务流程。
- 需要长期维护和迭代。DDD 的前期设计成本较高,如果项目做一版就扔了,不值得投入。
- 团队规模较大。多人协作时,清晰的领域边界能减少代码冲突和沟通成本。
不适合 DDD 的场景:
- 简单 CRUD 系统。比如后台管理系统的增删改查,业务逻辑本身就很简单,用传统三层架构足够了。
- 数据驱动型系统。比如数据分析平台,核心是数据处理和展示,不是业务规则。
- 短期项目或原型验证。DDD 的设计成本在前期,短期项目用不上。
一个简单的判断标准是:当业务复杂度开始超过技术复杂度时,就可以考虑引入 DDD。
小结
DDD 的核心目标,是让代码结构与业务结构保持一致,把业务规则集中到领域模型中,而不是分散在各个技术层。它解决的是复杂业务带来的设计和维护问题,而不是性能优化或高并发问题。对于业务简单的系统,传统三层架构已经足够;但当业务不断演进、规则越来越复杂时,DDD 能帮助我们更清晰地组织代码,降低维护成本,也让团队协作更加顺畅。
不过,真正开始实践 DDD,并不是先设计实体、聚合这些战术模型,而是先理解业务、划分边界。只有明确了不同业务的职责范围,并建立统一的业务语言,后续的模型设计才有基础。下一篇,我们就来聊聊 DDD 战略设计中的两个核心概念:限界上下文(Bounded Context)和统一语言(Ubiquitous Language)。