The Problem It Solves
String city = order.getCustomer().getAddress().getCity();
One innocent line, three hidden contracts. This code now knows that Order exposes Customer, Customer exposes Address, Address exposes City. Rename getAddress() → return a Location type? Breaks this line — and every other line like it scattered across the codebase, none of them findable from the class that owns the chain. The Law of Demeter (LoD) formalizes the fix: a method should talk only to its immediate friends — itself, its parameters, its fields, objects it creates — never to strangers reached through friends.
Friend Circle
┌──────────────────────────────┐
│ Method m() in class C │
│ │
│ this ──────────┐ │
│ parameters ────┼─ allowed │
│ fields' objs ──┤ talks │
│ new'd locally ─┘ │
└──────────┬───────────────────┘
▼
order.getCustomer().getAddress()...
↑ stranger reached THROUGH a friend
(friend's internals are not your friends)
The rule is about who you may address, not how many dots appear — the dot-count heuristic is a proxy, sometimes wrong.
The Fix — Tell, Don’t Ask
// ask through the chain (violates):
String city = order.getCustomer().getAddress().getCity();
// tell the friend what you want (complies):
String city = order.getShippingCity(); // Order navigates its own data
Order already owns its customer; let it answer. The traversal knowledge collapses into one class that legitimately has it, and internal restructuring stops rippling outward.
Where Chains Are Legitimate
- Fluent builders / same-module APIs:
stream().filter(...).map(...).collect(...)— every link is part of one designed contract returning self/same abstraction. LoD targets coupling to strangers’ internals, not designed chains. - Data structures you own: DTO field access within one module boundary.
- Query-style APIs where intermediate types are stable public contract.
What It Costs
- Delegating methods accumulate (
getShippingCity,getBillingCity, …) — the facade grows. - Over-application produces middle-men classes adding indirection without value.
Judgment call: apply hardest at module boundaries, loosely inside cohesive packages.
Real-World Stakes
- Refactoring safety: LoD-compliant callers survive representation changes silently — the property ORM-heavy codebases desperately need.
- Test simplification: mocking
order.getCustomer().getAddress()means mocking three levels deep; mockingorder.getShippingCity()mocks one.
Interview Signals
- Recognizing a train-wreck line and proposing the tell-dont-ask refactor on sight is standard mid-level signal.
- The experienced nuance: stating when chains are fine (fluent APIs) before applying the rule mechanically.
Premium Content
Unlock Law of Demeter and all premium lessons with a subscription.
From ₹199.99/year — See plans