> ## Documentation Index
> Fetch the complete documentation index at: https://meta.niceshare.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 迪米特法则

> 迪米特法则强调模块只与直接协作者通信，避免深层调用链。理解其起源、实践方法与过度使用时的代价。

<Info>
  **类别**: 原则<br />
  **类型**: 面向对象设计原则<br />
  **来源**: 美国东北大学 Demeter 项目，约 1987 年由 Ian Holland 等提出<br />
  **别名**: 最少知识原则
</Info>

<Note>
  **快速回答** — **迪米特法则**（Law of Demeter）主张：一个模块应只和“关系近”的对象交互，不要穿透多层对象内部结构。它的核心价值是降低耦合，让系统在结构变化时更稳。
</Note>

## 什么是迪米特法则？

**迪米特法则**（Law of Demeter）是一条边界规则：对象的方法应只调用自身、直接字段、方法参数以及本方法新建对象的方法。

> 让“直接协作者替你完成动作”，而不是“自己一路钻进别人的内部结构”。

在代码里，这通常表现为避免 `a.getB().getC().doX()` 这类“火车式调用链”。它和[单一职责原则](/zh/principles/single-responsibility)、[关注点分离](/zh/principles/separation-of-concerns)、[快速失败原则](/zh/principles/fail-fast)一起使用时，能显著降低改动扩散。

### 迪米特法则的三层理解

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

## 起源

该法则来自美国东北大学的 Demeter 项目，相关思想在 1980 年代后期由 Ian Holland 的研究与后续论文体系化。

它最初要解决的是可维护性问题：当调用方深度依赖被调对象的内部结构时，内部字段或对象关系一变，外层大量代码会连锁破坏。

后来这一原则被广泛吸收进工程实践，成为控制对象耦合、提升可演化性的常用设计准则。

## 核心要点

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

<Steps>
  <Step title="只与“朋友”通信，不与“陌生人”通信">
    方法优先调用自己和直接协作者的方法；跨多层对象取值往往意味着边界泄漏。
  </Step>

  <Step title="把深层导航改为意图方法">
    如果调用方需要深层数据，应该让直接协作者提供“业务意图方法”，而不是暴露内部结构。
  </Step>

  <Step title="把长链调用当作重构信号">
    频繁出现调用链通常说明职责分配不当，或模块边界不清晰。
  </Step>

  <Step title="控制纯度与可读性的平衡">
    机械地“处处包一层”会产生空转封装，应以降低耦合和表达意图为目标。
  </Step>
</Steps>

## 应用场景

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

<CardGroup cols={2}>
  <Card title="后端服务分层">
    通过服务层意图方法替代深层仓储-领域对象链式调用，减少跨层依赖。
  </Card>

  <Card title="前端状态管理">
    用 selector 或视图模型适配器替代深层 props 读取，降低组件耦合。
  </Card>

  <Card title="SDK 与公共库 API">
    暴露稳定入口，避免用户依赖库内部对象图细节。
  </Card>

  <Card title="团队代码评审">
    将“火车式调用链”列为高优先级重构信号，定期治理。
  </Card>
</CardGroup>

## 经典案例

在订单系统重构中，一个常见做法是将深层对象链读取改为聚合边界上的门面方法。公开工程复盘中，多团队都报告这种改造能降低“改一个模型牵动多模块”的连锁影响。

可量化指标通常是“单需求涉及文件数”和“发布后回归缺陷数”。当调用深度被压缩、边界方法稳定后，这两项指标通常会下降，说明变更面被有效收敛。

## 边界与失效场景

迪米特法则有效，但过度执行会产生副作用。

* **包装层膨胀**：过多中转方法会让代码变啰嗦、语义变弱。
* **接口贫血**：过度隐藏结构会影响高级场景的组合能力。
* **形式合规**：语法上“看似符合”，语义上仍可能强耦合。

## 常见误区

团队常把它误解为“禁止任何点号链式写法”。

<AccordionGroup>
  <Accordion title="误区：迪米特法则等于不能链式调用">
    **纠正**：稳定语义的 Fluent API 与泄漏内部结构的深层导航不是同一件事。
  </Accordion>

  <Accordion title="误区：包装方法越多越好">
    **纠正**：只有能表达意图并隔离变更的封装才有价值。
  </Accordion>

  <Accordion title="误区：它只适用于 OOP 教条场景">
    **纠正**：核心思想是“局部交互、控制扩散”，在任何架构都成立。
  </Accordion>
</AccordionGroup>

## 相关概念

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

<CardGroup cols={3}>
  <Card title="单一职责原则" href="/zh/principles/single-responsibility">
    模块职责越单一，协作边界越清晰，越容易遵守最少知识通信。
  </Card>

  <Card title="关注点分离" href="/zh/principles/separation-of-concerns">
    先做好层次隔离，才能从根源减少跨层穿透调用。
  </Card>

  <Card title="最小权限原则" href="/zh/principles/least-privilege">
    在安全领域采用同样思想：只授予最小必要访问范围。
  </Card>
</CardGroup>

## 一句话总结

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