领域驱动设计(Domain-Driven Design,DDD)自Eric Evans提出以来,已成为处理复杂业务系统的核心方法论。它不仅是技术架构,更是一种以业务领域为核心的软件设计哲学。在微服务与分布式系统成为主流的今天,理解DDD为何能超越传统分层架构、如何落地,对构建高内聚、可演进的复杂系统至关重要。
1. 核心理念:DDD为何而生?
DDD源于一个基本洞察:软件的复杂性并不来自技术,而来自业务领域本身。当业务逻辑错综复杂且频繁变化时,传统的以数据表驱动或分层抽象的架构,常导致业务逻辑散落各处(如Service层、数据库存储过程、前端校验),变得难以理解和维护。代码与业务概念逐渐脱节,成为“大泥球”。
DDD的核心应对策略是建立统一的领域模型,作为业务人员与开发团队的共同语言(通用语言),并将此模型作为系统设计的核心基础。所有技术实现(数据库、框架、UI)都应围绕且服从于领域模型,而非相反。
为了让您快速理解DDD与传统架构的根本区别,下表对它们进行了核心对比:
| 维度 | 传统分层架构 (如MVC, 经典三层) | 领域驱动设计 (DDD) | 核心差异解析 |
|---|---|---|---|
| 设计驱动力 | 数据与技术。常以数据库表结构为起点,向上构建CRUD服务。 | 业务与领域。以业务领域的概念、规则、流程为起点,向下映射技术实现。 | DDD是业务驱动,传统架构是数据/技术驱动。 |
| 核心关注点 | 数据的增删改查(CRUD),技术分层的清晰性。 | 领域模型的完整性、业务规则的显式表达、领域逻辑的高内聚。 | DDD追求业务逻辑的纯粹与内聚,传统架构追求技术职责的分离。 |
| 业务逻辑位置 | 分散。可能存在于Service层、数据库触发器/存储过程、甚至前端。 | 高度内聚于领域层的实体、值对象、领域服务中。 | DDD将业务逻辑收拢在领域层,是架构上的“釜底抽薪”。 |
| 与数据库关系 | 强耦合。模型常是数据库表的直接映射(贫血模型)。 | 弱耦合。领域模型反映业务,通过仓储(Repository)模式适配持久化。 | DDD通过仓储模式解耦领域与持久化细节。 |
| 应对复杂性的方式 | 通过更细的技术分层或引入新技术框架。 | 通过限界上下文(Bounded Context) 对庞大领域进行分治,降低认知负荷。 | DDD提供了战略性的业务分解工具。 |
| 适用场景 | 业务逻辑简单、以数据管理为主的内部系统、原型开发。 | 业务逻辑复杂、需要长期演进的商业核心系统。 | DDD在复杂业务系统中价值显著,在简单系统中可能过度设计。 |
2. DDD核心分层架构详解
经典DDD分层架构将系统垂直划分为四个层次,每一层都有其明确的职责和依赖关系,确保领域核心不受技术细节污染。

DDD4层架构目录工程结构:
- src
- it 集成测试模块
- java 集成测试代码
- resources 集成测试配置文件
- test 单元测试模块
- java 单元测试代码
- main 业务代码
- java
- interfaces 用户接口层
- facade 提供较粗粒度的调用接口,将用户请求委托给一个或多个应用服务进行处理
- rest REST API
- dubbo
- subscribe mq 事件订阅
注1:统一返回Result
注2:应该捕捉所有异常
- application 应用层
- assembler 实现 DTO 与领域对象之间的相互转换和数据交换
- event 存放事件相关代码,为了事件统一管理,将所有事件发布和订阅统一放到应用层,核心业务逻辑放到领域层
- publish 事件发布
- service 对领域服务或外部应用服务进行封装、编排和组合,对外提供粗粒度服务
- command 操作相关,必须调用领域层
- query 只放查询相关,可以直接调用持久层
注1:出参必须为 DTO
注2:入参为 Command 或 Query,唯一例外是单ID查询的场景
注3:Command 和 Query 有语义作用,避免复用
注4:通过 Spring Validation 来实现入参校验,减少非业务代码混杂业务代码中
- domain 领域层
- aggregate 聚合目录,按业务名称命名,如权限聚合
- entity 领域对象
- factory 从其他服务返回结果构建领域对象???
- valueobject
- event 存放事件实体和相关的业务逻辑代码
- service 存放领域服务代码
- repository 仓储,存放所有查询和持久化领域对象的代码,通常包括仓储接口和实现,仓储实现一般放在基础层,也可以直接放一起
- infrastructure 基础层
- config 存放配置相关代码
- client 存放跨服务接口、DTO
- service
- dto 存放 dto
- command
- query
- response
- common 存放消息、数据库、缓存、文件、总线、网关、公用的常量、枚举等
- enums 存放枚举
- cache 缓存相关服务
- mq mq相关配置
- db 数据库相关
- mapper 存放 mybatis dao 实现
- repositories 仓储实现
- po 持久化对象
- converter 用于封装底层,实现PO与DO一对多或多对多转换
- perisistence 存放 RepositoryImpl,调用 mapper
- ......
- util 存放平台、开发框架、第三方类库、通用算法等基础代码
- resources 配置文件
变更追踪
订单和订单明细对象,修改其中一个订单明细,其他数据不操作
场景:非聚合根实体变更操作
修改订单明细中其中一条价格,这条明细和订单总价需要变动,其他信息不变
持久化到数据库时,只需要修改 orderItem_x 条记录和 order 记录即可
贫血模式:
会记录对应的item id ,根据这个ID 更新
充血模式:
需要自己做对比,变更跟踪
解决方案:(待测试)
aggregate-persistence
各层职责深度解析
-
用户界面层 (Interface/API Layer)
-
职责:负责向用户(人或外部系统)展示信息、接收指令。不包含任何业务逻辑。
-
关键组件:
-
Controller/Rest API:接收请求,解包参数,调用应用服务,返回DTO。
-
DTO (Data Transfer Object):专为界面传输设计的、扁平化的数据结构,与内部领域模型解耦。
- ViewModel:将领域模型转换为前端可展示的格式。
-
-
示例:Web应用的Controller、移动端UI组件、RESTful API接口。
-
代码示例:
java
// Spring Boot Controller示例 @RestController @RequestMapping("/orders") public class OrderController { private final OrderApplicationService appService; @PostMapping public ResponseEntity<OrderDTO> createOrder(@RequestBody CreateOrderRequest request) { // 1. 参数基本校验(如非空) // 2. 调用应用服务,传入纯数据参数 OrderDTO orderDTO = appService.createOrder(request.getUserId(), request.getItems()); // 3. 返回给前端的DTO return ResponseEntity.ok(orderDTO); } }
-
-
应用层 (Application Layer)
-
职责:协调领域对象完成一个具体的用例(User Case)。它像乐队的指挥,不演奏具体乐器(业务规则),只安排流程。
-
关键组件:
-
应用服务 (Application Service):细粒度的服务,一个方法通常对应一个用户操作。
-
用例协调:组合多个领域对象或领域服务,管理事务边界和安全认证等横切关注点。
- 事务管理:确保跨多个领域操作的原子性(如Spring的
@Transactional)。 - 权限校验:验证用户权限(如JWT鉴权)。
-
- 示例:用户注册流程、订单支付流程。
-
代码示例:
java
@Service @Transactional // 事务管理在此层 public class OrderApplicationServiceImpl implements OrderApplicationService { private final OrderRepository orderRepository; private final InventoryService inventoryService; // 领域服务 @Override public OrderDTO createOrder(String userId, List<OrderItemRequest> items) { // 1. 协调流程:检查库存(调用领域服务) if (!inventoryService.isSufficient(items)) { throw new InsufficientInventoryException(); } // 2. 创建领域对象(工厂模式) Order order = Order.create(userId, items); // 3. 调用领域对象行为(此时业务逻辑在Order实体内部) order.confirm(); // 4. 持久化(调用基础设施层的仓储接口) orderRepository.save(order); // 5. 发布领域事件(可选,用于跨限界上下文通信) domainEventPublisher.publish(new OrderConfirmedEvent(order.getId())); // 6. 返回组装好的DTO return OrderAssembler.toDTO(order); } }
-
-
领域层 (Domain Layer)
-
职责:这是DDD的核心,承载和表达业务逻辑。包含业务领域的所有概念、规则、状态和流程。
-
关键组件:
-
实体 (Entity):具有唯一标识和生命周期,会随时间变化的对象(如
Order,User)。 -
值对象 (Value Object):描述事物特征但无标识的对象,通常不可变(如
Money,Address)。 -
聚合 (Aggregate) & 聚合根 (Aggregate Root):一组相关对象的集合,聚合根是外部访问的唯一入口,维护聚合内的业务一致性。
-
领域服务 (Domain Service):当某个操作不适合放在实体或值对象中时(如涉及多个实体或外部规则),用领域服务封装。
-
领域事件 (Domain Event):表示领域中发生的重要事情。
-
仓储接口 (Repository Interface):定义持久化领域对象的标准,实现在基础设施层。
-
- 示例:电商中的商品定价规则、金融中的风控模型。
-
代码示例(领域模型核心):
java
// 聚合根:订单 public class Order extends BaseAggregateRoot<Long> { private Long id; private String orderNumber; private CustomerId customerId; private OrderStatus status; private Money totalAmount; private List<OrderItem> items; // 内部实体列表,外部不可直接访问 // 【核心】静态工厂方法,封装创建逻辑 public static Order create(String userId, List<OrderItemRequest> itemRequests) { Order order = new Order(); order.id = OrderIdGenerator.nextId(); order.orderNumber = generateOrderNumber(); order.customerId = new CustomerId(userId); order.status = OrderStatus.CREATED; order.items = itemRequests.stream() .map(req -> new OrderItem(req.getProductId(), req.getQuantity(), req.getPrice())) .collect(Collectors.toList()); order.calculateTotal(); // 内部方法计算总价 return order; } // 【核心】实体行为方法,封装状态变更规则 public void confirm() { if (this.status != OrderStatus.CREATED) { throw new IllegalOrderStateException("Only CREATED orders can be confirmed."); } this.status = OrderStatus.CONFIRMED; // 记录领域事件 this.registerEvent(new OrderConfirmedEvent(this.id, LocalDateTime.now())); } // 值对象:订单项 @Getter public static class OrderItem { private final ProductId productId; private final Integer quantity; private final Money price; private final Money subTotal; // 通过构造器计算,确保不变性 public OrderItem(ProductId productId, Integer quantity, Money price) { this.productId = productId; this.quantity = quantity; this.price = price; this.subTotal = price.multiply(quantity); // 业务规则内聚 } } }
-
-
基础设施层 (Infrastructure Layer)
-
职责:为上层提供通用的技术能力实现,如数据库、消息队列、外部API调用等。。是系统的“工具箱”。
-
关键组件:
-
DAO/ORM、仓储实现 (Repository Implementation):数据访问对象如使用JPA/Hibernate/MyBatis实现
OrderRepository接口。 -
Message Queue消息中间件客户端:异步通信(如Kafka、RabbitMQ)。实现领域事件的发布。
- 外部API调用HTTP Client:调用外部服务(如Feign、RestTemplate)。
- 文件存储File Storage:文件存储(如AWS S3、本地磁盘)。
- 缓存等具体实现。
-
-
MySQL数据库、Redis缓存、SMTP邮件服务。
-
代码示例:
java
@Repository public class JpaOrderRepository implements OrderRepository { @PersistenceContext private EntityManager entityManager; @Override public Order findById(Long id) { // 复杂情况下,这里需要组装聚合(从多张表查询,重建Order及所有OrderItem) return entityManager.find(Order.class, id); } @Override public void save(Order order) { entityManager.persist(order); // 通常会在这里或应用层事务提交后,处理order中暂存的领域事件 publishEvents(order); } }
-
3、DDD(领域驱动设计)专用术语
1. 通用语言(Ubiquitous Language)
- 定义:团队(开发、产品、业务)共享的统一业务术语集,消除沟通歧义。
- 示例:在电商系统中,“购物车”而非“CartDTO”,“优惠券”而非“PromotionCode”。
2. 限界上下文(Bounded Context)
- 定义:将系统划分为独立的业务边界,每个边界内有自己的通用语言和模型。
- 示例:电商系统可划分为“用户上下文”、“订单上下文”、“支付上下文”。
3. 聚合根(Aggregate Root)
- 定义:聚合内的实体根,对外提供操作入口,确保聚合内数据一致性。
- 示例:
Order作为聚合根,管理OrderItem和Payment等关联实体。
4. 防腐层(Anti-Corruption Layer, ACL)
- 定义:在两个限界上下文交互时,隔离外部模型对内部模型的污染。
- 示例:将第三方支付系统的响应转换为内部统一的
PaymentResult对象。
5. 上下文映射(Context Map)
- 定义:描述多个限界上下文之间的关系(如共享内核、客户-供应商、遵奉者等)。
- 示例:用户上下文与订单上下文通过“共享内核”共享
User模型。
4、通用架构术语
1. 高内聚低耦合(High Cohesion, Low Coupling)
- 定义:模块内部功能紧密相关,模块间依赖最小化。
- 示例:领域层只依赖基础设施层的抽象接口,而非具体实现。
2. 依赖倒置(Dependency Inversion)
- 定义:高层模块不依赖低层模块,二者均依赖抽象(接口)。
- 示例:应用层依赖
UserRepository接口,而非具体的MySQL实现。
3. CQRS(命令查询职责分离)
- 定义:将写操作(Command)和读操作(Query)分离到不同模型。
- 示例:订单创建使用领域模型,订单查询使用缓存或读模型。
4. 事件溯源(Event Sourcing)
- 定义:通过事件序列记录状态变化,而非直接存储当前状态。
- 示例:用
OrderCreatedEvent、OrderPaidEvent等事件重建订单状态。
5. 最终一致性(Eventual Consistency)
- 定义:数据变更最终会在所有副本中一致,允许短暂不一致。
- 示例:分布式系统中,订单支付后库存更新可能有延迟。
4. 战略设计与战术设计:DDD的两大支柱
4.1 战略设计:划分问题空间
战略设计关注高层次业务划分,核心工具是限界上下文 (Bounded Context)。一个庞大的业务领域(如电商)可以划分为“订单上下文”、“库存上下文”、“支付上下文”、“物流上下文”。每个上下文都有自己独立的通用语言和领域模型,通过上下文映射(如防腐层ACL、发布/订阅事件)进行集成。这是微服务边界划分最重要的依据。
4.2 战术设计:构建解决方案
战术设计即在每个限界上下文内,运用上文提到的实体、值对象、聚合、领域服务等模式,构建出丰富的领域模型。这是将战略设计落地的关键。
5. DDD的应用场景与决策
适用场景:
-
业务逻辑高度复杂:领域有大量业务规则、状态转换和校验逻辑。
-
业务需要长期演进:团队庞大,需求频繁变更,需要清晰的模型来应对变化。
-
核心域项目:这是公司的核心竞争力所在,值得投入高设计成本以获得长期可维护性。
需谨慎或避免的场景:
-
简单CRUD管理后台:业务逻辑简单,DDD会带来不必要的复杂性。
-
一次性或短期项目:ROI过低。
-
技术探索型项目:业务域模糊,应优先探索技术可行性。
6. 现代架构中的DDD应用
DDD的思想已深刻影响现代软件架构:
-
微服务架构:限界上下文与微服务边界天然契合,DDD是微服务拆分最有力的理论指导。
-
事件驱动架构:领域事件是连接不同限界上下文或微服务的理想方式,实现松耦合集成。
-
CQRS (命令查询职责分离):常与DDD结合,命令端处理写操作,使用完整的领域模型保证一致性;查询端处理读操作,使用优化过的视图模型,两者通过事件同步。在复杂场景下,这能解决领域模型与查询性能之间的矛盾。
-
六边形架构 / 整洁架构:这些强调“领域核心独立”的架构理念,与DDD分层思想高度一致,常被用于实现DDD的底层技术架构。
7. 总结:从技术实现到业务价值
DDD的本质是一场思维的转变——从关注“如何存数据、做页面”转向关注“业务是什么、规则如何运转”。它通过一套系统的模式语言,帮助我们在复杂的业务迷宫中建立精确的坐标。虽然其学习曲线陡峭,初期实施成本较高,但对于处于数字化转型深水区、业务复杂度与日俱增的企业而言,投资于DDD是构建可持续演进、高质量核心系统的战略性选择。成功实践DDD的关键,在于业务专家与开发团队的紧密协作,以及对领域模型持续精炼的耐心。它最终带来的回报,是软件能够真正成为业务的敏捷反映,而非束缚业务的枷锁。
1233

被折叠的 条评论
为什么被折叠?



