迪米特法则强调对象只与“朋友”通信,避免火车式调用;应通过委托方法封装嵌套访问、返回不可变/抽象结果,并用协调者解耦多对象协作。

迪米特法则(Law of Demeter,LoD),又称“最少知识原则”,核心思想是:一个对象应当对其他对象有尽可能少的了解,只与“朋友”通信,不与“陌生人”直接交互。它不是要消灭所有耦合,而是通过限制调用链长度、隐藏内部结构,降低模块间依赖,提升可维护性和可测试性。
只调用“自己创建的”或“作为参数传入的”对象
这是LoD最直接的落地规则。对象只能调用自身属性、方法返回的对象(前提是该方法属于“朋友”类)、方法参数中的对象,以及自己创建的新对象。
- ✅ 允许:
order.getCustomer().getName()—— 如果getCustomer()是Order的直接方法,且Customer是Order的“朋友”(如被封装为私有字段或由构造器注入) - ❌ 禁止:
order.getShippingAddress().getCity().toUpperCase()—— 这是典型的“火车式调用”,暴露了Order → ShippingAddress → City三层内部结构,违反LoD - ✅ 替代做法:在
Order中提供高阶方法,如order.getShippingCity(),把细节封装起来
用委托代替深层导航
当需要获取嵌套对象的某个属性或执行某操作时,不要层层点取,而应在当前类中定义委托方法,把请求转给合适的协作对象。
- 例如,用户想查订单的收货人手机号:
❌user.getOrder().getDelivery().getReceiver().getPhone()
✅ 在User中加方法:getUserPhoneForLatestOrder(),内部协调Order和Delivery,对外只暴露语义清晰的接口 - 好处是:一旦
Delivery结构变更(比如拆分成Express和SelfPickup),只需修改委托方法,调用方完全无感
避免在方法中暴露内部组成对象
返回值类型应尽量抽象,不泄露实现细节。尤其警惕返回私有字段的引用(尤其是可变对象),这等于主动打破封装。
- ❌ 不推荐:
public List<item> getItems() { return items; }</item>—— 外部可直接修改内部列表 - ✅ 更安全:
public List<item> getItems() { return new ArrayList(items); }</item>或返回Collections.unmodifiableList(items) - ✅ 更彻底:
public int getItemCount()、public Item getItemAt(int i)—— 只暴露必要能力,不交出容器本身
用中介或外观模式解耦复杂协作
当多个对象天然需要协同完成某任务(如下单流程涉及库存、支付、通知),不要让客户端直接串联它们,而是引入一个协调者(如OrderService)统一调度。
- 客户端只需调用
orderService.place(order),无需知道库存是否充足、支付是否成功、短信是否发送 - 协调者内部按需调用各组件,但各组件之间不直接通信(如
InventoryService不调PaymentService) - 这种分层使单元测试更简单——可单独Mock协调者依赖的每个服务










