the Law of Demeter
In software engineering, we often talk about "coupling"—the degree to which one class relies on the internal details of another. One of the most famous guidelines for reducing coupling is the Law of Demeter (LoD), often summarized by the rule: "Don't talk to strangers."
The Law of Demeter challenges developers to write "shy" code. An object should know as little as possible about the structure or properties of anything else, including its own sub-components.
The Problem: "Train Wrecks" and Dot Counting
A violation of the Law of Demeter is often visually obvious. It is characterized by a long chain of accessors, often called a "navigation train" or a "train wreck."
When you see code like A.B.C.D.Method(), object A is showing that it knows exactly how B is built, how C is built, and where D lives. If the architecture of B changes, A breaks.
The Rules of Demeter
To obey the law, a method M in object O should only invoke methods of:
- Object
Oitself. - The parameters passed to
M. - Any objects created within
M. - Direct component objects (fields/properties) of
O.
Let's look at a concrete C# scenario involving a Reporting system.
❌ The Bad Example: The Violation
In this scenario, a Client class wants to run a report. However, to do so, it reaches deep into the Report object hierarchy to manually open a database connection.
Why is this bad?
- Tight Coupling:
ReportRunneris coupled toDatabaseandConnection. If you changeReportto use a cloud API instead of aDatabase,ReportRunnerbreaks. - Testing Nightmares: To unit test
ReportRunner, you have to mockReport,Database, andConnection. - Lack of Encapsulation: The
Reportclass is not in control of its own state. It is being micro-managed by theReportRunner.
✅ The Good Example: "Tell, Don't Ask"
To fix this, we apply the "Tell, Don't Ask" principle. We shouldn't ask the Report for its database and then ask the database for its connection. We should simply tell the Report to prepare itself.
We hide the delegation logic inside the classes where it belongs.
Why is this better?
- Loose Coupling:
ReportRunneronly depends onReport. You can completely swap out the internalDatabasefor aCsvLoaderwithout changing a single line of code inReportRunner. - Better Abstraction: The code reads like a sentence:
report.Initialize(). This reveals intent rather than implementation. - Easier Maintenance: Changes are localized. If the
Connectionlogic changes, you only update theDatabaseclass.
Another Classic Analogy: The Paperboy
A famous analogy for the Law of Demeter is the "Paperboy and the Wallet."
The Violation (The Mugging)
Imagine a paperboy comes to collect payment from a customer.
- Code:
customer.Wallet.GetMoney(5.00); - Reality: The paperboy reaches into the customer's pocket, takes out their wallet, and grabs 5 dollars. This is rude and assumes the customer has a wallet.
The Adherence (The Transaction)
The paperboy should just ask for payment.
- Code:
customer.Pay(5.00); - Reality: The customer decides how to pay. They might use a wallet, a checkbook, or change in their pocket. The paperboy doesn't know (and doesn't care) where the money comes from.
Summary
| Feature | Violation (Bad) | Adherence (Good) |
| Code Style | a.GetB().GetC().DoSomething() | a.DoSomething() |
| Coupling | High (Tight) | Low (Loose) |
| Knowledge | Object knows deep internal structure | Object only knows interface of neighbors |
| Maintenance | Fragile; changes ripple upwards | Robust; changes are contained |