Law of Demeter
A caller should talk to its immediate collaborators through meaningful operations rather than navigate their internal object graphs. This reduces how many structural details one change can break.
What you’ll understand
- A caller should talk to its immediate collaborators through meaningful operations rather than navigate their internal object graphs. This reduces how many structural details one change can break.
- Customer.shippingCity hides address traversal behind the operation the caller actually needs.
- Evaluate the tradeoff: Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.
Useful first: Classes and Objects
The idea and when to recognize it
A caller should talk to its immediate collaborators through meaningful operations rather than navigate their internal object graphs. This reduces how many structural details one change can break.
- Requirement: A dispatch screen needs a customer’s shipping city. The customer record can be stored in either an old or a new layout.
- Change to anticipate: Keep dispatch behavior stable when the customer’s internal address representation changes.
- Design goal: Customer.shippingCity hides address traversal behind the operation the caller actually needs.
Start with the concrete problem
A dispatch screen needs a customer’s shipping city. The customer record can be stored in either an old or a new layout.
Keep dispatch behavior stable when the customer’s internal address representation changes.
| Direct implementation | Revised design |
|---|---|
| Reaching through customer.profile.address.city couples dispatch to several internal structures. | Customer.shippingCity hides address traversal behind the operation the caller actually needs. |
| The baseline case can hide the problem. Compare the extension and boundary fixtures before accepting this design. | Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records. |
Responsibilities and contracts
Customer.shippingCity hides address traversal behind the operation the caller actually needs.
- Dispatch: Needs a city, not an address layout. Public operations: label(customer)
- Customer: Hides address storage. Public operations: shippingCity()
Read the design
Select a participant to inspect its responsibility and public operations. Follow the labeled relationships; an arrow indicates direction, while the legend distinguishes ownership, substitution, and temporary use.
Preparing the design walkthrough…
Follow the interaction
Choose a supplied workload and compare the direct and revised implementations. Step through the same operation in both languages. Object values are recorded after each highlighted statement; previous steps remain unchanged.
Preparing the design walkthrough…
Implementation and expected output
Read the complete example alongside its input and expected output. The implementation selector changes the displayed program; the language selector preserves your current scenario and playback position.
Preparing the design walkthrough…
Try the idea in another setting
A booking service can ask inventory.reserve(item) instead of mutating inventory.warehouse.shelf.items directly.
- Name the new client contract before adapting the example.
- Identify which state belongs to each object and who controls its lifetime.
- Write one normal case and one boundary case before extending the design.
Tradeoffs and interview takeaways
Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.
Common mistake: Reaching through customer.profile.address.city couples dispatch to several internal structures.
- Explain the choice: Customer.shippingCity hides address traversal behind the operation the caller actually needs.
- Challenge your choice: Delegating every tiny field can create noisy forwarding methods. Prefer operations named for a real caller need, and distinguish domain objects from intentionally transparent data-transfer records.
- Describe a requirement that would make the simpler implementation sufficient.
Design challenge and knowledge check
Preparing the design walkthrough…