迪米特法则要求一个类只调用直接朋友的方法,即自身创建、参数传入、字段持有或全局可访问的对象,禁止链式访问如user.getaddress().getcity().getname(),应封装为user.getcityname();委托需有明确业务语义,避免无意义中间层;须配合封装与不可变性才能真正降低耦合。

迪米特法则(Law of Demeter,LoD)的核心是“只与直接朋友交谈”,换句话说:一个类应该只调用它明确知道的对象的方法,而不应通过链式调用深入访问其他对象的内部成员。它不是为了彻底消灭依赖,而是控制依赖的深度和可见性,从而降低模块间的耦合度。
明确“直接朋友”的范围
一个类的“直接朋友”包括:
- 自己创建的对象(new 出来的实例)
- 方法参数传入的对象
- 自身属性持有的对象(字段/成员变量)
- 全局或静态可访问的对象(需谨慎使用)
例如,user.getAddress().getCity().getName() 违反了法则——user 和 city 不是朋友,中间隔着 address。应改为让 user 提供 getCityName() 方法,把导航逻辑封装在内部。
用委托代替链式访问
当需要获取下游数据时,优先由近端对象提供封装好的接口,而不是暴露内部结构:
- ❌ 错误做法:order.getCustomer().getProfile().getPreferredLanguage()
- ✅ 正确做法:order.getCustomerPreferredLanguage() 或 order.getCustomer().getPreferredLanguage()
后者把“客户偏好语言”这个语义收口在 Customer 类中,Order 无需了解 Profile 的存在,也避免因 Profile 结构变动导致 Order 报错。
警惕“中间人”类被过度泛化
有时为满足 LoD,会新增一层薄薄的委托类(如 UserFacade),但若它只做简单转发且无业务语义,反而增加冗余。判断标准是:
- 该方法是否表达了清晰的业务意图?(如 user.calculateAnnualDiscount() 而非 user.getCart().getItems().stream()...)
- 是否隐藏了实现细节或组合逻辑?
- 是否让调用方更易理解、更难出错?
如果只是机械转发,不如直接调整原有类的接口,或重构调用方逻辑。
配合封装与不可变性效果更佳
迪米特法则的效果依赖良好的封装基础:
- 对外暴露的字段尽量设为 private,提供有意义的 getter(而非返回内部集合引用)
- 返回集合时考虑用 unmodifiableList 或封装查询方法(如 hasItem(String id))
- 构造对象时尽量通过构造函数或 Builder 注入依赖,避免运行时随意替换内部组件
没有封装的“朋友”,只是把紧耦合从调用链转移到了字段访问上。










