迪米特法则强调“只跟直接朋友说话”,即仅调用自己创建、参数传入、字段持有或this的对象;禁止火车式调用,应通过委托方法封装深层访问;返回值需抽象且不可变,优先返回接口而非具体实现;复杂协作应引入协调者类。

迪米特法则(Law of Demeter,LoD)在 Java 面向对象开发中,不是限制“能不能调用”,而是约束“怎么调用”——重点在于控制调用链的深度和暴露的内部结构,从而把耦合关进封装的笼子里。
只跟“直接朋友”说话,不碰“陌生人”
Java 中一个类的“朋友”有明确范围:自己创建的对象、方法参数传入的对象、作为字段持有的对象(包括构造器注入或 setter 注入的)、以及 this 自身。其余都是“陌生人”。
- ✅ 允许:
order.getCustomer().getName()——前提是getCustomer()是Order的公开方法,且Customer是它直接持有的成员 - ❌ 禁止:
order.getShipping().getAddress().getZipCode()——这等于让调用方知道了 Order → Shipping → Address 三层嵌套,一旦任一环节改名、拆分或加校验,所有调用点都要改
用委托方法代替火车式调用
当业务需要获取深层数据时,不要层层点取,而是在拥有上下文的类里封装语义化方法。
- 比如订单要展示收货城市,别写
order.getDelivery().getLocation().getCityName() - 应该在
Order类中加一个方法:public String getDeliveryCity() { return delivery.getLocation().getCityName(); } - 这样上层只依赖
Order的契约,Delivery 内部重构为ExpressDelivery或PickupPoint时,只需改getDeliveryCity()实现,调用方完全无感
返回值要抽象,不泄露内部对象引用
避免把私有字段(尤其是可变对象)直接通过 getter 暴露出去,否则外部就能绕过封装修改状态。
- ❌ 危险写法:
public List<item> getItems() { return items; }</item>——外部可直接 add/remove,破坏一致性 - ✅ 安全做法:
public List<item> getItems() { return new ArrayList(items); }</item>或返回unmodifiableList,甚至只提供getItemCount()、hasItem(String sku)等高阶查询方法 - 返回接口类型(如
List而非ArrayList)也是 LoD 的体现——调用方无需知道底层用的是数组还是链表
必要时引入协调者,不搞多对多直连
当多个对象频繁协作(比如用户、订单、库存、优惠券联动),别让每个类都持有其他类的引用。可以用一个服务类或门面类来统一调度。
- 例如下单流程,不写
user.checkBalance(); order.validate(); inventory.reserve(); coupon.apply(); - 而由
OrderService.placeOrder(User, Order)统一协调,各模块只和OrderService交互 - 这既符合 LoD,也自然导向了分层架构和清晰的职责边界
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











