领域驱动设计(DDD)入门
一、领域、子域与限界上下文
领域(Domain):业务所关心的主题,即「系统要解决什么问题」。例如电商的领域包括商品、订单、支付、履约等。子域(Subdomain):把领域拆成更小的部分。常分为核心域(业务差异化所在,投入最多)、支撑域(必要但非差异化)、通用域(可买或复用,如认证、通知)。
限界上下文(Bounded Context):在一个明确的边界内,模型(术语、规则、实体含义)保持一致;跨边界则允许同一「词」有不同含义。例如「订单」在销售上下文中指「客户下单」,在履约上下文中指「拣货与发货任务」。每个限界上下文对应一套模型与职责,可对应一个模块或一个微服务。划分限界上下文是 DDD 中最影响架构的决策之一。
二、实体、值对象、聚合与领域事件
实体(Entity):有唯一标识、生命周期内可能变化的对象。例如订单(Order)、用户(User)。同一 ID 即同一实体,属性可变。
值对象(Value Object):无独立标识,由属性值定义;相等即所有属性相同,通常不可变。例如金额(Money)、地址(Address)。用于简化实体、避免「大实体」和重复逻辑。
聚合(Aggregate):一组实体与值对象的集合,有一个聚合根(Aggregate Root);外部只通过聚合根访问和修改内部。保证边界内的一致性。例如「订单」聚合:订单根 + 订单行项(值对象或实体),修改都经订单根。
领域事件(Domain Event):领域中「已经发生」的、其他上下文或模块可能关心的事实。例如 OrderPlaced、PaymentCompleted。用于限界上下文之间的解耦与异步协作,也便于审计与溯源。
三、统一语言与模型驱动设计
统一语言(Ubiquitous Language):业务、产品、开发用同一套术语讨论需求与设计——代码里的类名、方法名与业务用语一致,避免「表里不一」。术语来自领域专家与团队沟通,沉淀到模型与代码中。
模型驱动设计:领域模型不是画完就丢的图,而是直接反映在代码结构里。实体、值对象、聚合、领域事件都对应代码中的类型与边界;业务规则写在领域层,而不是散落在脚本或 SQL 里。这样模型与实现一致,需求变更时改模型即改代码,减少理解偏差。
统一语言要点
业务说什么,代码就写什么:类名、方法名、模块名与领域术语一致;需求讨论、设计文档与实现共用同一套词汇,减少「翻译」错误。
四、DDD 与架构的衔接
DDD 的限界上下文天然对应模块或服务边界:一个限界上下文可以是一个模块(模块化单体)、也可以是一个微服务。聚合的边界则影响事务与一致性:一个事务通常只改一个聚合;跨聚合用领域事件或最终一致性。分层上:领域层放实体、值对象、聚合、领域事件与领域服务;应用层(用例)编排领域对象、发事件、调基础设施;基础设施层做持久化、消息、外部 API。这样领域核心不依赖框架与数据库,可测、可替换。与上一章结合:先按 DDD 划清限界上下文与聚合,再决定是放在单体里做模块,还是拆成微服务。
一句话: DDD 用领域、子域、限界上下文划清模型边界,用实体、值对象、聚合、领域事件构建领域模型,用统一语言连接业务与代码,模型驱动设计让实现与模型一致。限界上下文对应模块或服务边界,聚合对应一致性边界,与架构衔接紧密。
五、小结
领域、子域、限界上下文:领域拆子域,限界上下文内模型一致、边界清晰。构建块:实体(有 ID)、值对象(无 ID、不可变)、聚合(根 + 一致性边界)、领域事件(已发生事实)。统一语言与模型驱动设计:业务术语即代码术语,模型即实现。与架构衔接:限界上下文对应模块/服务,聚合对应事务边界。下一章讲API 设计与版本管理,把 REST、契约、版本与兼容性说清楚。