依赖倒置与架构边界
依赖倒置与架构边界围绕 5 个章专属概念,以边界模型、决策轨迹、违规恢复和来源分层完成验收。
学习目标
- 能解释“依赖倒置与架构边界”如何区分运行时控制流与编译时源码依赖,并用边界接口让控制流跨越边界而源码仍指向内层政策
- 能逐项定位 源码依赖与控制流、稳定抽象、边界接口、插件架构、跨边界数据,并说明每个概念在当前来源边界内承担什么责任
- 能按 标出控制流 → 画出源码依赖 → 把接口移到内层 → 定义边界数据 → 替换外层插件 推演“展示订单结果”,检查“跨边界接口由内层需要定义,外层实现依赖该接口,内层源码不引用外层框架类型”
- 能注入“控制器直接返回 ORM 实体并让业务用例 import Web 与数据库包”,依据构建依赖图、端口所有权、请求响应数据结构、插件替换测试与控制流时序定位越界、撤销并用同一情境重放
为什么从“先画源码箭头再画运行时箭头,通过内层接口和外层实现让两种箭头可以朝相反方向”开始
区分运行时控制流与编译时源码依赖,并用边界接口让控制流跨越边界而源码仍指向内层政策。本页先画责任和依赖,再沿具体情境执行决策,最后主动制造一个边界违规;这种顺序把术语变成可以验证、推翻和恢复的设计合同。
“依赖倒置与架构边界”不是技术采购建议。它处理的是规则放在哪里、模型在哪个语境内成立、哪些变化可以被隔离,以及团队如何判断一条边界已经被穿透。最终功能可运行,只能证明快乐路径存在,不能证明结构允许安全演进。
来源、版次与课程边界
本页以 Martin 原始文章中的 Dependency Rule 与跨边界控制流示例为公开全文依据;Pearson 页面只核定对应原书身份,不声称取得书稿全文。
本专题不是某一本既有书的中文版,也不是把多位作者的文章拼成“原著章节”。课程主干分别取自 Eric Evans 的领域驱动设计体系与 Robert C. Martin 的整洁架构体系;CQRS、事件溯源和六边形架构始终标为扩展。以下链接承担不同事实责任:
- Pearson: Clean Architecture:核对 Robert C. Martin、第一版、2017 年与正式目录范围
- Robert C. Martin: The Clean Architecture:核对独立性目标、四层、依赖规则、跨边界控制流与简单边界数据
本页采用独立中文重写。能从公开全文或授权摘要核对的定义才作为来源事实;项目情境、交互实验、取舍表和练习答案均为本站教学设计。
核心概念与可观察责任
源码依赖与控制流
运行时可以由内层用例调用外层展示器,但编译时应由外层展示器实现内层接口;两种方向不同正是边界反转的关键。 在“展示订单结果”中,观察重点是跨边界接口由内层需要定义,外层实现依赖该接口,内层源码不引用外层框架类型。
稳定抽象
抽象应表达高层政策所需能力,并随政策演进;若接口只是复制数据库 SDK,所谓抽象仍由易变细节支配。 在“替换持久化”中,观察重点是构建依赖图、端口所有权、请求响应数据结构、插件替换测试与控制流时序。
边界接口
输入端口和输出端口明确用例接受什么、产出什么,接口归属在政策侧,从而避免业务层向外查询具体框架。 在“展示订单结果”中,观察重点是跨边界接口由内层需要定义,外层实现依赖该接口,内层源码不引用外层框架类型。
插件架构
数据库、界面和设备像插件一样接入核心政策;替换插件不要求核心反向理解每一种外部实现。 在“替换持久化”中,观察重点是构建依赖图、端口所有权、请求响应数据结构、插件替换测试与控制流时序。
跨边界数据
边界上传递简单、专用的数据结构,不能把 ORM 行、框架请求对象或数据库游标直接泄漏给内层。 在“展示订单结果”中,观察重点是跨边界接口由内层需要定义,外层实现依赖该接口,内层源码不引用外层框架类型。
一条可执行的设计判断
本页采用以下判断链:先画源码箭头再画运行时箭头,通过内层接口和外层实现让两种箭头可以朝相反方向。正常情况下必须持续保持“跨边界接口由内层需要定义,外层实现依赖该接口,内层源码不引用外层框架类型”;反例“控制器直接返回 ORM 实体并让业务用例 import Web 与数据库包”只改变一个关键条件,便于定位因果。
| 观察项 | 本页合同 |
|---|---|
| 最小正常情境 | 用例完成后需要把结果交给 Web Presenter |
| 边界或迁移情境 | Repository 从 SQL 改为远程 API |
| 必须保持 | 跨边界接口由内层需要定义,外层实现依赖该接口,内层源码不引用外层框架类型 |
| 首要违规 | 控制器直接返回 ORM 实体并让业务用例 import Web 与数据库包 |
| 验收证据 | 构建依赖图、端口所有权、请求响应数据结构、插件替换测试与控制流时序 |
先预测,再操作三个本页实验
实验一:边界与模型地图
操作前先预测“展示订单结果”里哪一侧拥有规则、哪一侧只是技术或协作细节。切换概念和情境后,检查“先画源码箭头再画运行时箭头,通过内层接口和外层实现让两种箭头可以朝相反方向”是否仍能解释三块区域的责任。
Boundary model
依赖倒置与架构边界:边界与责任地图
区分运行时控制流与编译时源码依赖,并用边界接口让控制流跨越边界而源码仍指向内层政策
切换最小情境
定位正式概念
architecturedomaindesign-03 · 当前观察
源码依赖与控制流:用例完成后需要把结果交给 Web Presenter
拥有用例接口和边界数据
↓
控制流穿越,源码依赖向内
↓
实现接口并适配具体技术
情境验收
用例调用内层定义的输出端口,外层 Presenter 实现该端口
易错边界与取舍
练习与答案
练习
问题 1:概念—边界—证据对照。 完成以下逐项核对:
- 源码依赖与控制流:写出它所在的边界、允许的依赖方向、一个最小反例和一份可观察证据。
- 稳定抽象:写出它所在的边界、允许的依赖方向、一个最小反例和一份可观察证据。
- 边界接口:写出它所在的边界、允许的依赖方向、一个最小反例和一份可观察证据。
- 插件架构:写出它所在的边界、允许的依赖方向、一个最小反例和一份可观察证据。
- 跨边界数据:写出它所在的边界、允许的依赖方向、一个最小反例和一份可观察证据。
问题 2:最小情境推演。 怎样验证“展示订单结果”没有靠最终功能碰巧通过?
问题 3:替代方案与恢复。 注入“控制器直接返回 ORM 实体并让业务用例 import Web 与数据库包”后,怎样比较修复与更简单方案?
本页小结
- 依赖倒置与架构边界的核心判断是:先画源码箭头再画运行时箭头,通过内层接口和外层实现让两种箭头可以朝相反方向。
- 正常路径以“用例调用内层定义的输出端口,外层 Presenter 实现该端口”验收,不能只检查接口返回成功。
- 边界路径以“外层实现变化,核心用例与其输入输出合同保持不变”验收,并保存构建依赖图、端口所有权、请求响应数据结构、插件替换测试与控制流时序。
- 如果“控制器直接返回 ORM 实体并让业务用例 import Web 与数据库包”仍可静默通过,说明边界只是图示,没有成为可执行约束。