Imagine you are working on an e-commerce system.
You need to get a customer's city.
A developer writes:
order
.getCustomer()
.getAddress()
.getCity()
.getName();Looks harmless.
A few months later:
The Address model changes.
Customer
└── Location
└── Cityinstead of:
Customer
└── Address
└── CityNow hundreds of places break.
Why?
Because many parts of the system knew:
Customer Internalsand
Address InternalsThe code became tightly coupled to the internal object structure.
This exact problem led to: Law of Demeter
Historical Background
The Law of Demeter was developed at: Northeastern University during the Demeter Project.
The primary researcher was: Karl Lieberherr.
The idea emerged from observing large software systems.
Teams repeatedly encountered:
High Coupling
Fragile Code
Difficult RefactoringA common root cause:
Objects knew too much about other objects.
The solution:
Limit what an object is allowed to know.
Hence: Principle of Least Knowledge
Official Definition
An object should only talk to its immediate friends.
Or more formally:
A method should only invoke methods belonging to:
1 Itself
this->calculateTax();2 Its Direct Members
repository.save();3 Objects Created Inside The Method
Logger logger;
logger.log();4 Parameters Passed To The Method
void process(Customer& customer)
{
customer.activate();
}Not arbitrary objects deep inside other objects.
The Intuition
Suppose you work in a company.
You need a document from Finance.
Bad approach:
Employee
-> Manager
-> Director
-> VP
-> CEO
-> Finance TeamYou navigate the entire organizational hierarchy.
Manager Structure
Director Structure
VP Structure
CEO StructureAny organizational change breaks the process.
Better:
Employee
-> ManagerThe manger gets the document.
The employee only knows:
Its Direct ContactThe employee doesn't need to know:
- Directors
- VPs
- Finance structure
This is exactly the Law of Demeter.
The Core Idea
The principle can be summarized as:
An object should know as little as possible about the internal structure of other objects.
Notice:
It does NOT say:
Don't use object.It does NOT say:
Don't call methods.It says:
Don't depend on internalsThe Famous Rule
A method should only talk to:
Self
Direct FriendsNot:
Friends of FriendsThink:
Don't talk to strangersUnderstanding Object Graphs
Consider:
class City
{
};
class Address
{
public:
City city;
};
class Customer
{
public:
Address address;
};
class Order
{
public:
Customer customer;
};Usage:
order.customer.address.city.getName();Object graph:
Order
|
Customer
|
Address
|
CityThe caller traverse:
4 Levels DeepThis creates strong coupling.
Train Wreck Code
One of the easiest Demeter violations to recognize.
Example:
order
.getCustomer()
.getAddress()
.getCity()
.getName();Looks like:
--------->a train.
Hence the nickname:
Train Wreck
Another example:
user
.getProfile()
.getSettings()
.getTheme()
.getColor();The caller depends on:
Profile
Settings
ThemeHuge coupling.
Why Train Wrecks Are Dangerous
Suppose:
Addressbecomes:
LocationNow:
order
.getCustomer()
.getAddress()breaks everywhere.
A single internal change causes:
Massive Ripple EffectsThis is fragile design.
Better Design:
Instead of:
order
.getCustomer()
.getAddress()
.getCityName();Provide behavior:
class Customer
{
public:
std::string getCityName() const;
};Usage:
order
.getCustomer()
.getCityName();Now:
Address Structure HiddenEncapsulation preserved.
Tell, Don't Ask
The Law of Demeter naturally leads to another major design principle:
Tell, Don't Ask
Bad:
if (order.getCustomer()
.getMembership()
.getLevel() == GOLD)
{
discount = 20;
}The caller extracts data.
Then make decisions.
Better:
if (order.isEligibleForGoldDiscount())
{
discount = 20;
}The object owns the decision.
The caller simply asks for behavior.
This creates better object-oriented design.
Fluent APIs: An Important Exception
Many students become confused here.
Consider:
query
.select("*")
.where("id=10")
.orderBy("name")
.execute();Looks like a train wreck.
But it usually isn't.
Why?
Because:
select()
where()
orderBy()return:
*thisthe same object.
You are not traversing:
Object A
-> Object B
-> Object C
-> Object DYou are repeatedly operating on:
Object ATherefore fluent APIs are usually acceptable.
Leave a comment
Your email address will not be published. Required fields are marked *


