跳转到主要内容
类别: 原则
类型: 面向对象设计原则
来源: 美国东北大学 Demeter 项目,约 1987 年由 Ian Holland 等提出
别名: 最少知识原则
快速回答迪米特法则(Law of Demeter)主张:一个模块应只和“关系近”的对象交互,不要穿透多层对象内部结构。它的核心价值是降低耦合,让系统在结构变化时更稳。

什么是迪米特法则?

迪米特法则(Law of Demeter)是一条边界规则:对象的方法应只调用自身、直接字段、方法参数以及本方法新建对象的方法。
让“直接协作者替你完成动作”,而不是“自己一路钻进别人的内部结构”。
在代码里,这通常表现为避免 a.getB().getC().doX() 这类“火车式调用链”。它和单一职责原则关注点分离快速失败原则一起使用时,能显著降低改动扩散。

迪米特法则的三层理解

  • 入门:少写长链调用,让直接对象暴露你真正需要的动作。
  • 实践:用意图清晰的门面方法隐藏深层导航逻辑。
  • 进阶:把它当作“变更半径控制器”,用于架构边界设计。

起源

该法则来自美国东北大学的 Demeter 项目,相关思想在 1980 年代后期由 Ian Holland 的研究与后续论文体系化。 它最初要解决的是可维护性问题:当调用方深度依赖被调对象的内部结构时,内部字段或对象关系一变,外层大量代码会连锁破坏。 后来这一原则被广泛吸收进工程实践,成为控制对象耦合、提升可演化性的常用设计准则。

核心要点

迪米特法则不是语法洁癖,而是协作边界管理方法。
1

只与“朋友”通信,不与“陌生人”通信

方法优先调用自己和直接协作者的方法;跨多层对象取值往往意味着边界泄漏。
2

把深层导航改为意图方法

如果调用方需要深层数据,应该让直接协作者提供“业务意图方法”,而不是暴露内部结构。
3

把长链调用当作重构信号

频繁出现调用链通常说明职责分配不当,或模块边界不清晰。
4

控制纯度与可读性的平衡

机械地“处处包一层”会产生空转封装,应以降低耦合和表达意图为目标。

应用场景

你可以在编码、评审和 API 设计阶段持续应用这条原则。

后端服务分层

通过服务层意图方法替代深层仓储-领域对象链式调用,减少跨层依赖。

前端状态管理

用 selector 或视图模型适配器替代深层 props 读取,降低组件耦合。

SDK 与公共库 API

暴露稳定入口,避免用户依赖库内部对象图细节。

团队代码评审

将“火车式调用链”列为高优先级重构信号,定期治理。

经典案例

在订单系统重构中,一个常见做法是将深层对象链读取改为聚合边界上的门面方法。公开工程复盘中,多团队都报告这种改造能降低“改一个模型牵动多模块”的连锁影响。 可量化指标通常是“单需求涉及文件数”和“发布后回归缺陷数”。当调用深度被压缩、边界方法稳定后,这两项指标通常会下降,说明变更面被有效收敛。

边界与失效场景

迪米特法则有效,但过度执行会产生副作用。
  • 包装层膨胀:过多中转方法会让代码变啰嗦、语义变弱。
  • 接口贫血:过度隐藏结构会影响高级场景的组合能力。
  • 形式合规:语法上“看似符合”,语义上仍可能强耦合。

常见误区

团队常把它误解为“禁止任何点号链式写法”。
纠正:稳定语义的 Fluent API 与泄漏内部结构的深层导航不是同一件事。
纠正:只有能表达意图并隔离变更的封装才有价值。
纠正:核心思想是“局部交互、控制扩散”,在任何架构都成立。

相关概念

迪米特法则与以下概念组合时效果更稳定。

单一职责原则

模块职责越单一,协作边界越清晰,越容易遵守最少知识通信。

关注点分离

先做好层次隔离,才能从根源减少跨层穿透调用。

最小权限原则

在安全领域采用同样思想:只授予最小必要访问范围。

一句话总结

迪米特法则的本质是缩短依赖触角,让模块只与直接协作者协作,从而降低改动连锁风险。