尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

DDD 系列:通用语言和上下文映射

DDD 系列:通用语言和上下文映射
📅 发布时间:2026/7/13 8:11:39

上一篇文章中,我们学习了领域、子域和限界上下文,知道了 DDD 的战略设计首先要解决一个问题:哪些业务应该放在一起,哪些业务应该分开。

不过,边界划分出来只是第一步。

真实项目中,即使大家都在讨论“订单”,产品、开发、测试和财务理解的也可能不是同一个东西。如果这些词没有统一,模型、接口和代码就容易各说各话;边界之间没有明确关系,服务调用也会慢慢变成互相依赖。

所以这一篇我们继续学习战略设计里面的两个概念:

  • 通用语言(Ubiquitous Language):解决同一个上下文内部如何统一表达;
  • 上下文映射(Context Map):解决不同限界上下文之间如何协作。

一、为什么业务和代码总是对不上

产品说:“用户提交订单后,可以取消订单。”

这句话听起来没有问题,但开发真正开始写代码时,一堆问题就出来了:

  • “提交订单”是保存草稿、创建成功,还是已经支付;
  • 用户取消和客服关闭是不是同一个动作;
  • 取消后需不需要释放库存、退回优惠券;
  • 已经支付的订单到底叫取消还是退款。

如果这些问题没有说清楚,代码里面很可能出现下面这种方法:

updateOrderStatus(orderId,4);

4是什么意思,为什么能改成4,修改之后还要做什么,只看这行代码完全不知道。

另一个开发可能又写了一个:

closeOrder(orderId);

这时候“取消订单”和“关闭订单”到底是不是一回事,也没人能说清楚。

问题的根源不是方法名没起好,而是团队没有先统一业务语言。

二、什么是通用语言

通用语言英文叫 Ubiquitous Language,也有人翻译成统一语言。

通用语言是一套由业务人员和开发人员共同建立,并且在同一个限界上下文中持续使用的业务语言。

也就是说,团队在讨论业务、写需求、画模型、定义接口和编写代码时,应使用同一套含义明确的词。

1. 不是开发自己定义一套术语

通用语言不是开发人员关起门来给类和字段起名字。

它应该来自业务讨论,由产品、业务、开发和测试共同确认。

比如业务上明确区分:

  • 用户主动放弃未支付订单,叫作取消订单;
  • 超时未支付由系统终止,叫作关闭订单;
  • 已支付订单退回资金,叫作退款。

那么代码里面也应该保留这种区别:

order.cancel();order.close();order.refund();

而不是全部写成:

order.updateStatus(status);

前一种写法能直接表达业务动作,后一种写法只是修改数据。

2. 通用语言只在特定上下文中成立

上一篇文章中我们提到,限界上下文会给模型划定生效范围。

通用语言同样受这个边界约束。同一个词在不同限界上下文中,可以有不同含义。

还是以电商系统为例:

限界上下文“商品”的含义重点关注的信息
商品上下文可维护和展示的商品资料名称、类目、品牌、详情
交易上下文用户下单时购买的交易项成交价、购买数量、优惠快照
库存上下文可以入库、出库和锁定的库存单元SKU、可用量、锁定量、仓库

它们都可能说“商品”,但是关注的不是同一个模型。

如果为了追求全系统统一,强行让三个上下文共用一个Product类,这个类最后就会同时包含展示、交易、库存等字段,改任何一处都可能影响其他模块。

所以,通用语言追求的是上下文内部一致,不是整个系统只有一套万能模型。

这张图强调的不是三个对象应该怎么设计,而是语言和模型都有明确的生效边界。

三、通用语言怎么落到代码里

通用语言不能只停留在会议纪要或者术语表里,它最终要进入代码。

如果开会时说“取消订单”,代码中却叫changeStatus,团队很快还会回到各说各话的状态。

1. 类名要体现业务角色

不要只根据数据库表名机械生成对象。

比如交易上下文中的订单,可以使用Order;支付上下文里记录支付过程的对象,可以使用PaymentOrder。即使它们在数据库里都带有order字样,也不代表它们是同一个业务对象。

2. 方法名要体现业务动作

业务代码里面,优先使用有业务含义的方法:

order.submit();order.cancel();order.confirmPayment();

少用看不出意图的名字:

order.update();order.handle();order.process();

一个好的业务方法名,应该让我们不看方法实现也能大概知道它在做什么。

3. 状态和规则也要使用业务词汇

下面这种状态虽然能运行,但是阅读成本很高:

privateIntegerstatus;

业务允许的情况下,可以把状态表达得更明确:

publicenumOrderStatus{WAITING_FOR_PAYMENT,PAID,CANCELED,CLOSED}

需要注意,这里不是说所有字段都必须改成枚举,也不是说用了枚举就是 DDD。

重点是:代码中的概念和业务讨论中的概念要对应得上。

4. 发现歧义时及时更新语言

通用语言不是项目启动时整理一次,以后就不变了。

随着业务深入,我们可能会发现原来的词不够准确。比如最开始只有“退款”,后来业务增加了仅退款、退货退款、部分退款,这时候模型和代码也要跟着调整。

如果一个词在会议中需要反复解释,或者不同人总是给出不同理解,通常就说明这个词还没有定义清楚。

四、什么是上下文映射

限界上下文划分完成后,各个上下文并不会完全隔离。

下单需要查询商品,下单成功需要锁定库存,支付成功需要通知订单,订单完成以后可能还要增加会员积分。

这些协作关系放在一起,就是上下文映射。

上下文映射是对多个限界上下文之间关系、依赖方向和协作方式的明确描述。

它关注的不是某个类怎么写,而是下面这些问题:

  • 哪个上下文依赖哪个上下文;
  • 谁是上游,谁是下游;
  • 双方是否共享模型;
  • 外部模型进入当前上下文时要不要转换;
  • 上游发生变化时,下游会受到多大影响。

通俗一点讲,限界上下文告诉我们“边界画在哪里”,上下文映射告诉我们“边界之间怎么打交道”。

五、常见的上下文映射关系

上下文映射有不少模式。这里先介绍项目中比较容易遇到的几种,重点理解它们解决什么问题,不需要一上来背所有英文缩写。

1. 客户方—供应方

客户方—供应方也叫 Customer/Supplier。

上游上下文提供能力,下游上下文使用能力。下游对接口有明确诉求,并且可以参与上游接口或发布计划的协商。

比如商品上下文向交易上下文提供商品查询能力。交易上下文是使用方,它可能要求接口稳定返回商品是否可售、当前价格等信息。

这种关系不是简单的“我调你接口”,重点在于:下游需求能够进入上游的协作计划。

2. 防腐层

防腐层也叫 Anticorruption Layer,简称 ACL。

当外部系统的模型和当前上下文差异较大时,我们不直接把外部对象带进领域模型,而是在边界处做一次转换。

例如外部库存系统返回:

{"sku_id":"SKU-1001","available_qty":20,"locked_qty":3}

当前交易上下文真正关心的可能只是“本次购买数量是否可用”。这时候可以通过防腐层转换成当前上下文自己的表达:

publicinterfaceInventoryGateway{booleanisAvailable(StringskuId,intquantity);}

外部接口字段、协议和异常处理都留在适配实现中,领域代码只依赖自己能理解的能力。

**防腐层的核心价值,是保护当前上下文的模型不被外部模型污染。**至于防腐层具体怎么写,后面的进阶章节会单独展开,这里先理解它在上下文关系中的位置。

3. 开放主机服务和发布语言

开放主机服务叫 Open Host Service,发布语言叫 Published Language。

当一个上下文需要向多个调用方稳定提供能力时,可以设计一套公开、稳定的服务协议,并使用双方都能理解的数据格式进行交互。

常见形式包括 REST API、RPC 接口、消息事件、OpenAPI 文档和明确版本的 DTO。

这里的关键不是用了 HTTP 还是 MQ,而是对外契约要稳定,并且不能直接暴露上下文内部模型。

4. 其他常见关系

关系适用场景注意事项
合作关系两个上下文共同开发一项业务一方修改契约时,要同步评估另一方
共享内核双方共享少量含义完全一致的模型或规则共享范围必须小,并由双方共同维护
遵奉者下游无法要求上游调整,只能接受其模型和接口接入简单,但下游容易受上游模型影响
各行其道集成成本大于收益,各自实现更简单不是所有重复都值得抽成共享能力

六、用一个电商场景串起来

假设现在有商品、交易、库存、支付和会员五个限界上下文。

它们之间可能存在下面这些关系:

上下文关系协作方式
商品 → 交易商品提供公开查询接口,交易使用稳定 DTO 获取商品信息
交易 → 库存交易通过防腐层调用库存能力,只保留“锁定库存”等本地业务语义
支付 → 交易支付成功后发布消息,交易根据契约更新订单支付结果
交易 → 会员订单完成后通知会员增加成长值,双方通过公开事件格式协作

把这些关系画成上下文映射图,大概就是下面这样:

图中的实线表示同步调用,虚线表示异步事件。交易上下文调用库存能力时增加了一层模型转换,避免库存上下文的字段和协议直接进入交易模型。

这里需要注意,上下文映射表达的是业务边界之间的关系,不等于微服务调用拓扑图。

一个限界上下文可以暂时和另一个限界上下文部署在同一个应用里,它们仍然是两个模型边界。反过来,一个微服务如果塞进了多个互相混乱的业务模型,也不能因为已经拆成服务,就认为边界一定合理。

我们可以用下面几个问题检查映射是否清楚:

  1. 调用关系的上下游是否明确;
  2. 对外契约由谁维护;
  3. 上游字段变化会不会直接冲击下游领域模型;
  4. 外部异常在哪里转换;
  5. 双方使用的同名概念是否真的含义一致;
  6. 这段共享或依赖是否真的有必要。

如果这些问题回答不出来,说明边界虽然画了,但上下文之间的关系还没有梳理清楚。

这些模式是描述真实关系的工具,不是必须全部套用的设计检查表。

七、总结

这一篇我们继续学习了 DDD 的战略设计,主要整理了通用语言和上下文映射。

简单总结一下:

  • 通用语言用于统一同一个限界上下文内部的业务表达;
  • 通用语言要进入需求、模型、接口和代码,不能只停留在会议上;
  • 同一个词在不同限界上下文中可以有不同含义;
  • 上下文映射用于描述不同限界上下文之间的依赖和协作关系;
  • 防腐层可以隔离外部模型,公开服务契约可以稳定上下文之间的协作;
  • 上下文映射不等于微服务调用图,更不能代替真实业务边界分析。

到这里,我们已经知道了怎么划分边界、怎么统一边界内的语言,以及边界之间怎么协作。

不过这些结果不能只靠几个人坐在会议室里面拍脑袋决定。下一篇文章,我们继续学习事件风暴,看看怎么让业务、产品、开发和测试一起把业务流程、关键事件和边界梳理出来。

相关新闻

  • STM32与TB6593FNG的直流电机控制方案设计与优化
  • STM32控制TPS61170实现高效升压转换方案
  • TMC7300与PIC18F67K40组合优化有刷直流电机控制

最新新闻

  • MATLAB IMU姿态解算实战包:加速度计+陀螺仪融合输出实时俯仰/横滚/偏航角
  • Claude Mythos Preview:AI驱动的自主漏洞挖掘能力阶跃
  • SARIMAX金融时间序列建模:从平稳性检验到可解释预测
  • IntelliJ IDEA 2026.1 Build vs Maven:5个关键场景下的编译行为差异与选择
  • 遗传算法工程化实战:编码选择、选择压力与终止策略三重突破
  • 向日葵远程官网下载安装图文教程(附2026最新版安装包) - sdfsafafa

日新闻

  • AI推荐结果怎么优化:适合深圳少儿素质培训机构的GEO服务商哪家好?全程零代码SAAS操作
  • RAG 实战教学完全指南
  • 企业级API网关架构深度解析:IBM Microgateway的技术实现与选型指南

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号