第四章:依赖方向与稳定抽象原则

在模块边界设计中,依赖关系不仅仅是代码层面的引用,更是架构信任链路的载体。**稳定依赖原则(SDP)**、**稳定抽象原则(SAP)** 与 **依赖倒置原则(DIP)** 共同构成了管理模块间依赖方向的黄金三角。

依赖方向与稳定抽象关系图(DIP + SDP/SAP) 高层业务策略(不稳定度 I 低) 低层实现细节(不稳定度 I 高) «接口» 业务抽象(稳定) «接口» 数据抽象(稳定) 支付请求(PolicyService) 支付网关(GatewayImpl) 实现 实现 运行时控制流(向下流动) 核心要点:依赖线(箭头)指向稳定抽象层(蓝色),控制流(虚线)从高层流向低层。这就是“依赖倒置”。
架构要点:依赖关系是一种编译时契约。SDP 和 SAP 定义了哪些模块应该成为这种契约的承载者。DIP 则给出了实现这种契约的具体编码模式。

4.1 依赖方向判定:不稳定度(I)的计算

SDP 的核心思想是:不稳定的模块(易变)应该依赖稳定的模块(不变),反之则要警惕。我们通过计算模块的 不稳定度(I) 来量化这种风险。

  • 传入依赖(Ca): 有多少外部模块依赖你(扇入)?
  • 传出依赖(Ce): 你依赖了多少外部模块(扇出)?

公式:I = Ce / (Ca + Ce) —— I 的取值范围是 [0, 1]。

模块类型 I 值范围 依赖路径风险 边界设计建议
基础框架 / 工具库 0 ~ 0.1 极高:所有人依赖它,它不能轻易变 必须抽象,采用外观模式封装变化
业务领域层 0.1 ~ 0.3 较低:有一定的传入依赖,无实现细节 作为依赖目标,应全为接口
具体实现类 0.7 ~ 1.0 高:经常随配置或需求变更 应仅被组合根引用,或被注入
循环依赖双方 计算失真 致命:无法单独发布或测试 必须打破重构,引入中间接口

4.2 稳定性与抽象度的平衡(SAP)

SAP 指出:一个模块如果非常稳定(I=0),则它必须是抽象的(A≈1),以便能够被扩展;如果一个模块非常不稳定(I=1),则它可以是具体的(A≈0)。

主序列距离(D):D = |A + I - 1|。最理想的组件落在“主序列”上(D=0)。D 值过大(如超过0.5)的组件通常预示着设计问题。

风险识别案例:假设有一个 ConfigLoader 模块,所有模块都依赖它获取配置(Ca 高,I=0.1)。但它直接读取具体 JSON 文件(Na 低,A=0.1)。则 D = |0.1+0.1-1| = 0.8。这个模块落入了“痛苦区”:它非常具体且非常稳定。任何配置格式的变更都会导致所有依赖模块重新编译。

标准做法:对这个 ConfigLoader 提取 ConfigProvider 接口(提高 A 值),并利用依赖注入(DIP)让具体实现离开主链路。

4.3 依赖倒置在边界上的落地

DIP 是实施 SDP 和 SAP 的战术手段。它要求高层次模块不应依赖低层次模块,两者都应依赖抽象。

  • 信任链路: 方向从具体的生产者指向抽象的消费者(接口)。在大型业务系统中,我们通常会在多个微服务之间建立这种信任,让调用方依赖服务端的接口包,而非实现包。
  • 数据流与控制流: 数据流顺着依赖方向流动(调用者传入数据),控制流则逆着依赖方向流动(调用者控制流程)。
  • 选型权衡: 引入接口层会增加系统复杂度和间接性。对于团队内部、几乎没有变化的模块,过度抽象反而降低开发效率。通常建议:跨团队边界、易变逻辑、外部集成点必须使用 DIP。
边界设计陷阱:不要在模块边界上使用“漏失抽象”。如果创建的接口(如 IBusinessService)只有一个实现且几乎不变,则这个抽象是无效的。它占用了维护成本却没有带来灵活性。务必将抽象服务于易变点。

4.4 落地步骤与验收标准

在具体项目中落实依赖方向与稳定抽象原则,建议按以下步骤执行,并在架构看板中持续监控。

  1. 依赖扫描与矩阵化: 使用 Architecture Eval 或定制脚本,生成全量模块的依赖矩阵。标记所有违反单向依赖的循环。
  2. 计算度量: 对每个模块计算 Ca、Ce、I、A、D 五元组。生成散点图,标出位于“痛苦区”(D>0.5)的模块。
  3. 识别变与不变: 访谈各模块所有者,标记出易变业务逻辑和稳定基础设施。
  4. 制定重构清单:
    • 对落在痛苦区的稳定具体模块:提取接口。
    • 对跨越边界的直接 new:改为工厂或 DI 注入。
    • 对循环依赖:引入中间层或事件总线。
  5. 设置门禁: 在 CI 中引入依赖规则引擎,禁止新模块的 D 值超过团队容忍阈值(如 < 0.6)。

验收标准

维度 验收指标 验证方式
SDP 合规 无反向依赖;I 值高的模块不依赖 I 值低的模块 依赖结构矩阵(DSM)
SAP 合规 所有稳定模块(I<0.3)的 A 值 >0.7 自动化静态检查
DIP 实施 所有跨边界调用必须通过接口;禁止直接引用实现类 Code Review + ArchUnit
信任链路 模块间有明确的契约包(API 包),无实现泄漏 包依赖分析
持续集成建议:将依赖规则检测接入 GitLab CI 的基本门禁。当出现 D > 0.5 的提交时,流水线给出黄色警告;当出现循环依赖或依赖方向错误时,直接红色阻断。