03 · 战略设计(下):限界上下文与上下文映射

03 · 战略设计(下):限界上下文与上下文映射

划完子域,接下来回答:每块业务内部的模型边界在哪?边界之间怎么打交道?本篇讲限界上下文的判断方法、最容易犯的"大一统模型"错误,以及六种上下文映射模式。


3.1 限界上下文:模型的户口所在地

限界上下文(Bounded Context)是模型的适用边界------在这条边界内,通用语言的每个词都有唯一、明确的含义。

判断方法一句话:当同一个词在不同场景下含义或规则不同时,就该切上下文了。

3.2 经典案例:一个"商品",三种形态

初学者最容易犯的错:建一个巨大的 Product 类,所有模块共用。看看它的下场:
#mermaid-svg-xQWEQboHeHI9GILp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-xQWEQboHeHI9GILp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-xQWEQboHeHI9GILp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-xQWEQboHeHI9GILp .error-icon{fill:#552222;}#mermaid-svg-xQWEQboHeHI9GILp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xQWEQboHeHI9GILp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-xQWEQboHeHI9GILp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xQWEQboHeHI9GILp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xQWEQboHeHI9GILp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-xQWEQboHeHI9GILp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xQWEQboHeHI9GILp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xQWEQboHeHI9GILp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xQWEQboHeHI9GILp .marker.cross{stroke:#333333;}#mermaid-svg-xQWEQboHeHI9GILp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xQWEQboHeHI9GILp p{margin:0;}#mermaid-svg-xQWEQboHeHI9GILp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xQWEQboHeHI9GILp .cluster-label text{fill:#333;}#mermaid-svg-xQWEQboHeHI9GILp .cluster-label span{color:#333;}#mermaid-svg-xQWEQboHeHI9GILp .cluster-label span p{background-color:transparent;}#mermaid-svg-xQWEQboHeHI9GILp .label text,#mermaid-svg-xQWEQboHeHI9GILp span{fill:#333;color:#333;}#mermaid-svg-xQWEQboHeHI9GILp .node rect,#mermaid-svg-xQWEQboHeHI9GILp .node circle,#mermaid-svg-xQWEQboHeHI9GILp .node ellipse,#mermaid-svg-xQWEQboHeHI9GILp .node polygon,#mermaid-svg-xQWEQboHeHI9GILp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xQWEQboHeHI9GILp .rough-node .label text,#mermaid-svg-xQWEQboHeHI9GILp .node .label text,#mermaid-svg-xQWEQboHeHI9GILp .image-shape .label,#mermaid-svg-xQWEQboHeHI9GILp .icon-shape .label{text-anchor:middle;}#mermaid-svg-xQWEQboHeHI9GILp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-xQWEQboHeHI9GILp .rough-node .label,#mermaid-svg-xQWEQboHeHI9GILp .node .label,#mermaid-svg-xQWEQboHeHI9GILp .image-shape .label,#mermaid-svg-xQWEQboHeHI9GILp .icon-shape .label{text-align:center;}#mermaid-svg-xQWEQboHeHI9GILp .node.clickable{cursor:pointer;}#mermaid-svg-xQWEQboHeHI9GILp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-xQWEQboHeHI9GILp .arrowheadPath{fill:#333333;}#mermaid-svg-xQWEQboHeHI9GILp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xQWEQboHeHI9GILp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xQWEQboHeHI9GILp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xQWEQboHeHI9GILp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-xQWEQboHeHI9GILp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xQWEQboHeHI9GILp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-xQWEQboHeHI9GILp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xQWEQboHeHI9GILp .cluster text{fill:#333;}#mermaid-svg-xQWEQboHeHI9GILp .cluster span{color:#333;}#mermaid-svg-xQWEQboHeHI9GILp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xQWEQboHeHI9GILp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-xQWEQboHeHI9GILp rect.text{fill:none;stroke-width:0;}#mermaid-svg-xQWEQboHeHI9GILp .icon-shape,#mermaid-svg-xQWEQboHeHI9GILp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-xQWEQboHeHI9GILp .icon-shape p,#mermaid-svg-xQWEQboHeHI9GILp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-xQWEQboHeHI9GILp .icon-shape .label rect,#mermaid-svg-xQWEQboHeHI9GILp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-xQWEQboHeHI9GILp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-xQWEQboHeHI9GILp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-xQWEQboHeHI9GILp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 上帝类 Product(300+ 字段)

标题 · 详情 · 图片 · SKU · 库存数量

成交价快照 · 仓库位置 · 营销文案......
商品目录页:只需要标题图片详情

但被迫加载和维护全部字段
库存模块:只关心 SKU 和数量

但改库存要动整个 Product 类
订单模块:只需要成交快照

但商品改价,历史订单语义被污染

DDD 的做法是拆成三个模型,各归各的上下文:
#mermaid-svg-FAWpKQEN5d2Uc75A{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FAWpKQEN5d2Uc75A .error-icon{fill:#552222;}#mermaid-svg-FAWpKQEN5d2Uc75A .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FAWpKQEN5d2Uc75A .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FAWpKQEN5d2Uc75A .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FAWpKQEN5d2Uc75A .marker.cross{stroke:#333333;}#mermaid-svg-FAWpKQEN5d2Uc75A svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FAWpKQEN5d2Uc75A p{margin:0;}#mermaid-svg-FAWpKQEN5d2Uc75A .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A .cluster-label text{fill:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A .cluster-label span{color:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A .cluster-label span p{background-color:transparent;}#mermaid-svg-FAWpKQEN5d2Uc75A .label text,#mermaid-svg-FAWpKQEN5d2Uc75A span{fill:#333;color:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A .node rect,#mermaid-svg-FAWpKQEN5d2Uc75A .node circle,#mermaid-svg-FAWpKQEN5d2Uc75A .node ellipse,#mermaid-svg-FAWpKQEN5d2Uc75A .node polygon,#mermaid-svg-FAWpKQEN5d2Uc75A .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FAWpKQEN5d2Uc75A .rough-node .label text,#mermaid-svg-FAWpKQEN5d2Uc75A .node .label text,#mermaid-svg-FAWpKQEN5d2Uc75A .image-shape .label,#mermaid-svg-FAWpKQEN5d2Uc75A .icon-shape .label{text-anchor:middle;}#mermaid-svg-FAWpKQEN5d2Uc75A .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FAWpKQEN5d2Uc75A .rough-node .label,#mermaid-svg-FAWpKQEN5d2Uc75A .node .label,#mermaid-svg-FAWpKQEN5d2Uc75A .image-shape .label,#mermaid-svg-FAWpKQEN5d2Uc75A .icon-shape .label{text-align:center;}#mermaid-svg-FAWpKQEN5d2Uc75A .node.clickable{cursor:pointer;}#mermaid-svg-FAWpKQEN5d2Uc75A .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FAWpKQEN5d2Uc75A .arrowheadPath{fill:#333333;}#mermaid-svg-FAWpKQEN5d2Uc75A .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FAWpKQEN5d2Uc75A .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FAWpKQEN5d2Uc75A .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FAWpKQEN5d2Uc75A .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FAWpKQEN5d2Uc75A .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FAWpKQEN5d2Uc75A .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FAWpKQEN5d2Uc75A .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FAWpKQEN5d2Uc75A .cluster text{fill:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A .cluster span{color:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FAWpKQEN5d2Uc75A .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FAWpKQEN5d2Uc75A rect.text{fill:none;stroke-width:0;}#mermaid-svg-FAWpKQEN5d2Uc75A .icon-shape,#mermaid-svg-FAWpKQEN5d2Uc75A .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FAWpKQEN5d2Uc75A .icon-shape p,#mermaid-svg-FAWpKQEN5d2Uc75A .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FAWpKQEN5d2Uc75A .icon-shape .label rect,#mermaid-svg-FAWpKQEN5d2Uc75A .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FAWpKQEN5d2Uc75A .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FAWpKQEN5d2Uc75A .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FAWpKQEN5d2Uc75A :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 商品已上架/改价事件
下单时同步快照
库存已扣减事件
订单上下文
OrderItem

· 成交价快照

· 数量

· 购买时名称快照
库存上下文
StockItem

· SKU 编码

· 占用数量

· 可售数量

· 预警阈值 · 仓库位置
商品上下文
Product

· 标题 / 详情 / 图片

· 分类 / 标签

· 营销文案

· 上下架状态

关键认知:

  1. 三个类都叫"商品相关的模型",但没有一个是同一个东西,也不应该是;
  2. 订单上下文的 OrderItem 绝不引用商品上下文的 Product 对象------只存下单那一刻的快照。否则商品改价、改图,历史订单的语义就被污染;
  3. 上下文之间靠领域事件或 API 同步数据,互不侵入对方的模型。

3.3 上下文数量怎么把握

#mermaid-svg-2osZ6XqGxzgHJHFy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2osZ6XqGxzgHJHFy .error-icon{fill:#552222;}#mermaid-svg-2osZ6XqGxzgHJHFy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2osZ6XqGxzgHJHFy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2osZ6XqGxzgHJHFy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2osZ6XqGxzgHJHFy .marker.cross{stroke:#333333;}#mermaid-svg-2osZ6XqGxzgHJHFy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2osZ6XqGxzgHJHFy p{margin:0;}#mermaid-svg-2osZ6XqGxzgHJHFy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy .cluster-label text{fill:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy .cluster-label span{color:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy .cluster-label span p{background-color:transparent;}#mermaid-svg-2osZ6XqGxzgHJHFy .label text,#mermaid-svg-2osZ6XqGxzgHJHFy span{fill:#333;color:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy .node rect,#mermaid-svg-2osZ6XqGxzgHJHFy .node circle,#mermaid-svg-2osZ6XqGxzgHJHFy .node ellipse,#mermaid-svg-2osZ6XqGxzgHJHFy .node polygon,#mermaid-svg-2osZ6XqGxzgHJHFy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2osZ6XqGxzgHJHFy .rough-node .label text,#mermaid-svg-2osZ6XqGxzgHJHFy .node .label text,#mermaid-svg-2osZ6XqGxzgHJHFy .image-shape .label,#mermaid-svg-2osZ6XqGxzgHJHFy .icon-shape .label{text-anchor:middle;}#mermaid-svg-2osZ6XqGxzgHJHFy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2osZ6XqGxzgHJHFy .rough-node .label,#mermaid-svg-2osZ6XqGxzgHJHFy .node .label,#mermaid-svg-2osZ6XqGxzgHJHFy .image-shape .label,#mermaid-svg-2osZ6XqGxzgHJHFy .icon-shape .label{text-align:center;}#mermaid-svg-2osZ6XqGxzgHJHFy .node.clickable{cursor:pointer;}#mermaid-svg-2osZ6XqGxzgHJHFy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2osZ6XqGxzgHJHFy .arrowheadPath{fill:#333333;}#mermaid-svg-2osZ6XqGxzgHJHFy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2osZ6XqGxzgHJHFy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2osZ6XqGxzgHJHFy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2osZ6XqGxzgHJHFy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2osZ6XqGxzgHJHFy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2osZ6XqGxzgHJHFy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2osZ6XqGxzgHJHFy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2osZ6XqGxzgHJHFy .cluster text{fill:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy .cluster span{color:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2osZ6XqGxzgHJHFy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2osZ6XqGxzgHJHFy rect.text{fill:none;stroke-width:0;}#mermaid-svg-2osZ6XqGxzgHJHFy .icon-shape,#mermaid-svg-2osZ6XqGxzgHJHFy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2osZ6XqGxzgHJHFy .icon-shape p,#mermaid-svg-2osZ6XqGxzgHJHFy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2osZ6XqGxzgHJHFy .icon-shape .label rect,#mermaid-svg-2osZ6XqGxzgHJHFy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2osZ6XqGxzgHJHFy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2osZ6XqGxzgHJHFy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2osZ6XqGxzgHJHFy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 上下文数量怎么定?
信号:过少

· 一个上下文里模型字段大量可空

· 同一个词在代码里有两个含义

· 改一处影响多个不相关模块
信号:过多

· 一个上下文只有一个类

· 跨上下文调用占请求耗时大头

· 团队规模撑不起独立维护
合并
拆分或合并

经验值:一个限界上下文对应一个小团队(两披萨以内)能在数周内完整理解并维护的模型。宁少勿滥------上下文越少,集成的成本越低。

3.4 上下文映射:边界之间的六种契约

上下文之间必然要协作,**上下文映射(Context Mapping)**定义协作的"契约"。六种模式:

模式 一句话解释 典型场景 协作成本
防腐层(ACL) 两上下文间加一层翻译,保护自己模型不被外部污染 对接第三方支付、遗留系统 中
客户-供应商 下游定义需求,上游按需供给,双方协商排期 库存服务于订单 低
开放主机服务(OHS) 上游提供标准化协议/SDK,供所有下游接入 统一认证服务 一次性高、边际低
发布语言(PL) 双方约定公开的报文/事件格式(常与 OHS 搭配) 领域事件 Schema 低
共享内核 两上下文共享一小部分模型,需协同变更 同团队维护的紧密模块 高(慎用)
各行其道 互不集成,靠人工/文件同步 一次性数据导出 最低

最常用的是防腐层

规则:凡是调用"不受你控制的系统"(三方接口、遗留系统),中间必须垫一层翻译对象,绝不让外部报文字段直接穿透进你的领域模型。

java 复制代码
// 三方支付回调原文:字段含义由别人定义,随时会变
class ThirdPartyPayNotify { String tranStat; String amt; String merId; }

// 防腐层:翻译成自己领域的事件
class PaymentAcl {
    PaymentReceived translate(ThirdPartyPayNotify notify) {
        return new PaymentReceived(
                OrderId.of(notify.merId),
                Money.of(notify.amt),
                mapStatus(notify.tranStat));   // "01"=成功 → PAID,翻译规则集中一处
    }
}

好处:三方改字段、换服务商,只改 ACL 一个类;领域模型全程不认识三方的报文格式。

一个完整电商的上下文映射图

#mermaid-svg-2KQ9rZVRRCeGb4Yu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .error-icon{fill:#552222;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .marker.cross{stroke:#333333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu p{margin:0;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .cluster-label text{fill:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .cluster-label span{color:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .cluster-label span p{background-color:transparent;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .label text,#mermaid-svg-2KQ9rZVRRCeGb4Yu span{fill:#333;color:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .node rect,#mermaid-svg-2KQ9rZVRRCeGb4Yu .node circle,#mermaid-svg-2KQ9rZVRRCeGb4Yu .node ellipse,#mermaid-svg-2KQ9rZVRRCeGb4Yu .node polygon,#mermaid-svg-2KQ9rZVRRCeGb4Yu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .rough-node .label text,#mermaid-svg-2KQ9rZVRRCeGb4Yu .node .label text,#mermaid-svg-2KQ9rZVRRCeGb4Yu .image-shape .label,#mermaid-svg-2KQ9rZVRRCeGb4Yu .icon-shape .label{text-anchor:middle;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .rough-node .label,#mermaid-svg-2KQ9rZVRRCeGb4Yu .node .label,#mermaid-svg-2KQ9rZVRRCeGb4Yu .image-shape .label,#mermaid-svg-2KQ9rZVRRCeGb4Yu .icon-shape .label{text-align:center;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .node.clickable{cursor:pointer;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .arrowheadPath{fill:#333333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2KQ9rZVRRCeGb4Yu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2KQ9rZVRRCeGb4Yu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2KQ9rZVRRCeGb4Yu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .cluster text{fill:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .cluster span{color:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2KQ9rZVRRCeGb4Yu rect.text{fill:none;stroke-width:0;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .icon-shape,#mermaid-svg-2KQ9rZVRRCeGb4Yu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .icon-shape p,#mermaid-svg-2KQ9rZVRRCeGb4Yu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .icon-shape .label rect,#mermaid-svg-2KQ9rZVRRCeGb4Yu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2KQ9rZVRRCeGb4Yu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2KQ9rZVRRCeGb4Yu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2KQ9rZVRRCeGb4Yu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户-供应商

下单扣库存
客户-供应商

支付成功发货
客户-供应商

领券用券
开放主机服务

统一发 Token
开放主机服务
防腐层 ACL

三方报文翻译
交易上下文

(核心域)
库存上下文
物流上下文
营销上下文
认证上下文
支付网关(外部系统)

读图要点:

  1. 箭头方向 = 依赖方向。交易上下文是核心域,依赖它的支撑域按它的节奏供给;
  2. 对外部系统(支付网关)一定经过 ACL,图中能看到明确的"隔离带";
  3. 认证是典型 OHS:一个上游服务所有下游,避免每个上下文各自对接登录逻辑。

3.5 上下文映射与团队协作

上下文映射同时是组织架构的镜子(康威定律):

映射模式 背后的团队关系
客户-供应商 两个团队,下游有话语权,排期可协商
防腐层 两个团队互不信任或外部无法协商,各管各的
共享内核 同一个团队或 pair 极紧密的两个团队
各行其道 没有正式协作渠道(警惕:多半是组织问题)

实用推论:如果上下文映射图上出现"共享内核",先检查是不是两个团队在互相改对方的代码------多半该拆团队或拆上下文,而不是共享模型。

3.6 常见疑问

Q:限界上下文 = 微服务吗?

不是,但关系密切。限界上下文是逻辑边界;微服务是物理部署单元。理想状态下一个上下文一个服务,但落地时可以是"多个上下文先住一个单体,各自独立模块"(09 篇详细展开)。

Q:怎么验证上下文边界划对了?

两个体检项:① 每个上下文内部能否用 5~10 句通用语言讲清自己的职责;② 跨上下文的调用/事件是否在真实业务流程中自然出现,还是为了凑数据硬拉的。后者说明边界划错了。


本篇小结:同一个词含义不同就切上下文;"商品"三种形态是最经典的判例;上下文之间用六种映射模式定契约,其中防腐层是保护模型的头号利器;映射图同时反映组织结构。战略设计到此完成,下一篇进入战术设计------边界内部的类怎么写。

关于作者

985 计算机硕士,十年头部大厂技术经历,现任金融公司高级架构师。面试近千人,培养 50+ 新人。

我维护着一个全栈技术博客(yuandianit.com),把踩过的坑整理成了实战文档,覆盖 Java 全栈、AI 应用(RAG 链路 / Agent / 多模型接入)、微信支付完整链路与对账、Wiki 知识库。

相关推荐
say_fall4 小时前
【AI大模型】MCP 模型上下文协议:客户端-服务器架构、JSON-RPC 消息与能力协商、工具发现与调用链路、与函数调用的分工
服务器·人工智能·架构
Decay__5 小时前
14_MySQL 高可用与容灾架构 —— MGR / InnoDB Cluster / Keepalived+VIP / 双主 / 读写分离 / 两地三中心
运维·数据库·sql·mysql·架构
猿人谷5 小时前
Surrogate Model:让进化算法学会“预测”,为什么它正在成为智能优化的重要技术?
后端·算法·架构
Kari115 小时前
企业级智能体平台怎么选:腾讯云ADP与其他主流技术路线的架构对比
架构·云计算·腾讯云
泯泷6 小时前
AI时代,中层还要替公司传多少次话?
人工智能·架构
Dawson Zhu6 小时前
【LLM推理与Serving⑧】多机多卡Serving:TP/PP/负载均衡与弹性扩缩容全攻略
人工智能·语言模型·架构·aigc·agi
Bode_20028 小时前
大语言模型与运筹规划双闭环共生(LLM-OR):体系架构、理论机理与落地实践
人工智能·语言模型·架构
空奈qwq8 小时前
【Kafka 从入门到实战】从手写一个队列到生产级消息中间件:架构、分区、消费组、零拷贝全解析
分布式·架构·kafka
李兆龙的博客8 小时前
从一到无穷大 #108:Meta 的 AI 存储架构——BLOB 重构与跨地域数据加载
人工智能·重构·架构
聪明的笨猪猪8 小时前
政务知识库AI架构选型:强合规约束下的架构决策与落地路径
经验分享·架构·ai编程·政务