DDD 核心概念梳理:从领域模型到领域事件 title: DDD 核心概念梳理从领域模型到领域事件date: 2026-07-09tags: DDD, 架构设计excerpt: 系统梳理领域模型、统一语言、限界上下文、聚合、领域服务、应用服务、基础设施和领域事件等 DDD 核心概念帮助理解领域驱动设计的基本建模思路。draft: falseDDD 核心概念梳理从领域模型到领域事件领域驱动设计Domain-Driven DesignDDD强调以业务领域为中心组织软件模型。它并不是简单地把数据库表映射成对象而是希望通过代码准确表达业务概念、业务规则和业务流程。在复杂业务系统中DDD 的价值主要体现在三个方面让代码结构更贴近真实业务降低业务人员与开发人员之间的沟通成本将核心业务规则沉淀到稳定、清晰的领域模型中。本文围绕 DDD 中几个常见核心概念进行梳理包括领域模型、统一语言、限界上下文、聚合、领域服务、应用服务、基础设施和领域事件。1. 领域模型业务规则的代码化表达领域模型是 DDD 的核心。它用于描述某个业务领域中的核心对象、状态变化、业务规则和对象之间的关系。需要注意的是领域模型并不等同于数据表模型。数据库表更关注数据如何存储而领域模型更关注业务规则如何表达。以订单系统为例订单模型通常不只是一个Order数据表而是包含订单基本信息订单明细收货地址支付状态发货状态取消规则退款规则金额计算规则。这些对象和规则共同构成了订单领域模型。一个好的领域模型应该能够回答业务中有哪些核心对象这些对象之间有什么关系哪些规则必须被严格保证对象状态在什么条件下可以变化2. 统一语言让业务表达和代码表达保持一致统一语言是团队在需求讨论、文档编写、代码命名和接口设计中共同使用的一套业务语言。它的目标是减少沟通歧义让业务人员和开发人员在同一套概念体系下协作。例如在优惠券系统中如果业务上统一称为“优惠券”代码中就不应同时出现多种含义接近但边界不清的命名CouponVoucherDiscountTicketPromotionCard如果这些词表示的是同一个业务概念就应该统一命名如果它们表示不同概念则需要明确各自的业务边界。统一语言的核心原则是业务中怎么表达代码中就尽量怎么表达。这样可以让代码本身具备更强的业务可读性。3. 限界上下文明确模型的适用边界限界上下文用于划定一个模型生效的业务边界。在这个边界内部概念含义保持一致离开这个边界后同一个词可能具有不同含义。大型系统中一个概念往往会被多个业务模块使用但不同模块关注的角度并不相同。以“用户”为例上下文关注点账号上下文登录账号、密码、手机号、权限订单上下文下单人、收货地址、支付信息营销上下文用户标签、消费等级、优惠券偏好客服上下文投诉记录、售后历史、服务等级虽然这些模块都可能使用“用户”这个词但它们关心的内容不同因此不一定适合共用同一个User模型。限界上下文的意义在于不要试图用一个大而全的模型覆盖所有业务场景而应该在清晰边界内建立适合当前业务的模型。4. 聚合维护一组对象的一致性聚合是一组业务上强相关的对象集合。它们通常需要作为一个整体维护业务一致性。聚合不是简单的对象组合而是用于回答一个更关键的问题哪些对象必须一起修改哪些规则必须一起保证以订单为例一个订单聚合可能包含Order ├── OrderItem ├── Address └── PaymentInfo订单金额、订单明细、优惠信息和运费之间存在强关联。如果外部系统可以随意修改订单明细就可能导致订单金额、支付状态和实际商品信息不一致。因此这些对象需要被组织在同一个聚合中由统一入口控制修改行为。5. 聚合根聚合对外的唯一入口每个聚合都应该有一个聚合根。聚合根是外部访问聚合内部对象的唯一入口。仍以订单聚合为例Order通常就是聚合根。外部代码不应直接修改OrderItem而应通过Order提供的方法完成操作order.changeItemQuantity(itemId,quantity);这样Order就可以在修改前统一检查业务规则例如订单是否允许修改商品数量是否合法订单金额是否需要重新计算当前订单状态是否支持变更。相比之下如果外部直接操作订单明细orderItem.setQuantity(10);就可能绕过订单规则破坏聚合内部一致性。聚合根的核心作用是控制聚合内部对象的变更保证业务规则不会被绕过。6. 领域服务承载跨对象的领域行为有些业务行为明显属于领域逻辑但并不适合放到某个实体或值对象中。此时可以使用领域服务。领域服务不是普通工具类它应该表达明确的业务动作或业务规则。例如转账行为涉及两个账户A 账户扣款 B 账户入账 检查账户状态 检查余额 记录交易流水这个行为不完全属于 A 账户也不完全属于 B 账户因此可以抽象为TransferDomainService领域服务适合处理跨多个实体的业务操作不自然属于单个对象的业务规则具有明确领域含义的计算或判断逻辑。7. 应用服务编排业务用例的执行流程应用服务负责组织一次完整的业务用例。它主要关注流程编排而不是承载核心业务规则。以创建订单为例应用服务可能负责1. 接收创建订单请求 2. 查询用户和商品信息 3. 创建订单聚合 4. 调用领域逻辑计算金额 5. 保存订单 6. 发布订单创建事件其中“订单是否允许创建”“订单金额如何计算”“订单状态如何变化”等规则应尽量放在领域模型或领域服务中而不是堆在应用服务中。应用服务更像是业务流程的协调者它负责把领域对象、仓储、消息、事务等组件组织起来完成一个用例。8. 基础设施提供技术实现能力基础设施层负责支撑系统运行所需的技术能力包括数据库读写Redis 缓存消息队列文件存储第三方接口调用ORM 框架系统配置。例如订单保存可以通过仓储接口表达OrderRepository而具体实现可以放在基础设施层OrderRepositoryImpl其内部可以使用 MyBatis、JPA、Redis 或其他技术组件。领域模型不应该关心数据最终存储在 MySQL、PostgreSQL 还是 MongoDB 中。它只需要表达业务概念和业务规则具体技术细节应由基础设施层处理。9. 领域事件表达已经发生的业务事实领域事件用于描述领域中已经发生的、具有业务意义的事实。领域事件通常使用过去式命名例如OrderCreated PaymentCompleted CouponIssued UserRegistered以订单支付成功为例支付完成后系统可能需要执行多个后续动作修改订单状态通知仓库发货增加用户积分发送通知消息生成账单流水。如果这些逻辑全部写在支付流程中代码会变得臃肿且耦合严重。更合理的方式是发布一个领域事件PaymentCompletedEvent然后由不同模块监听该事件各自完成后续处理。领域事件的价值在于表达业务中已经发生的重要事实降低模块之间的直接依赖支持业务流程的异步扩展让核心业务动作和后续响应逻辑解耦。10. 应用服务与领域服务的区别应用服务和领域服务容易混淆可以从职责上区分。对比项应用服务领域服务关注点用例流程编排领域规则和业务行为是否包含核心业务规则不应包含可以包含典型职责调用领域对象、保存数据、发布事件处理跨对象业务逻辑命名示例OrderApplicationServicePricingDomainService常见场景创建订单、提交支付、发起退款价格计算、库存分配、账户转账简单来说应用服务负责“流程怎么走”领域服务负责“业务规则怎么判断、怎么算”。11. 各概念之间的关系可以用下面的结构理解 DDD 中这些概念的关系限界上下文划定业务边界 ↓ 统一语言统一边界内的概念表达 ↓ 领域模型用代码表达业务对象和规则 ↓ 实体 / 值对象 / 聚合组织领域模型 ↓ 聚合根控制聚合内部一致性 ↓ 领域服务处理跨对象的业务行为 ↓ 应用服务编排业务用例流程 ↓ 基础设施提供数据库、缓存、消息等技术能力 ↓ 领域事件通知业务中已经发生的重要事实这些概念不是孤立存在的而是共同服务于一个目标让复杂业务系统的代码结构更加清晰、稳定并且能够随着业务变化持续演进。12. 示例用户下单流程中的 DDD 概念以“用户下单”为例可以将 DDD 概念对应到具体业务中DDD 概念示例限界上下文订单上下文统一语言订单、订单明细、收货地址、支付状态领域模型Order、OrderItem、Address、PaymentStatus实体Order具有唯一订单号值对象Address只描述地址信息聚合Order 聚合包含 OrderItem 和 Address聚合根Order领域服务PriceCalculateService处理复杂价格计算应用服务OrderApplicationService编排创建订单流程基础设施OrderRepositoryImpl负责订单持久化领域事件OrderCreatedEvent表示订单创建成功通过这个例子可以看到DDD 并不是为了增加概念复杂度而是为了让业务结构在代码中有更清晰的表达。