Table of Contents
Introduction
The law of Demeter states that objects should only interact with their immediate surroundings.
Specifically:
- Each unit should have only limited knowledge about other units
- Objects should only talk to friends, don’t talk to strangers
- Only talk to immediate friends
That means, the methods of an object should only call methods on other objects that:
- are instantiated within it
public void lodCompliant1() { var x = new Dog(); x.bark();//ok to call on methods of objects that initiated within the method }
- are fields of the class it resides in
class Dog { private Owner owner; private void greet() { System.out.println("Hello " + owner.getName());//OK to call on methods of class' fields } }
- passed to it as parameters
private void inspect(Human human) { System.out.println("Inspecting human: " + human.getName()); }
- are global variables that are accessible in the method’s scope
class Sample { private static Weather weather = new Weather(); private void inspect(Human human) { if (weather.isBad()) { System.out.println("Take a day off due to bad weather"); return; } System.out.println("Inspecting human: " + human.getName()); } }
And it should not call methods on objects that:
- returned by other methods
Here is a simple diagram to illustrate the principle:
Friends, Strangers???
OK, some new terminologies here. Let’s me explain:
- Friends: objects that are closely related to the current object and that the current object needs to interact with in order to perform its intended functionality. For example, if you have a Car class, the Engine and Manufacturer objects associated with that car might be considered friends.
- Immediate Friends: objects that are directly contained within the current object, and that the current object needs to interact with in order to perform its intended functionality. Take the car example above, if the car contains an Engine object, the Engine object would be considered an immediate friend of the User object.
- Strangers: objects that are not closely related to the current object, and that the current object does not need to interact with in order to perform its intended functionality. For example, if you have a User class, an object representing the user’s credit card details might be considered a stranger.
The purpose of this principle
What does this principle try to achieve? It helps promote loose coupling between objects thus make it simpler to extend and modify code without breaking existing functionalities.
Remember, these are recommendations, not strict rules. The main spirit is to limit the interactions between objects to only those that are necessary and relevant, and to avoid tightly coupling objects that are not closely related.
Violations of the law of Demeter
An easy way to detect the violation of the law of Demeter is to look for method chaining. If you spot some code similar to this, there is a good chance that’s a violation of the law:
public void violation01() { var zipCode = user.getAddress().getZipcode(); }
In the law of Demeter, friends of friends are not friends.
Here is a concrete example of the law’s violation
class Customer { private String name; public String getName() { return name; } } class Order { private Customer customer; private String description; public String getDescription() { return description; } public Customer getCustomer() { return customer; } } class OrderPrinter { private order Order; public void printOrder() { System.out.println("Order details: " + order.getDescription() + " by user " + order.getCustomer().getName()); } }
The code on the line 29 violates the law of Demeter because the OrderPrinter
class only knows about the Order
object. However, it calls the getName
method on the returned value of the getCustomer
method, which is a stranger to the OrderPrinter
object.
Violations’ remedies
One possible fix of the above is to provide a method to get the customer’s name inside the Order
class. Here is the code:
class Customer { private String name; public String getName() { return name; } } class Order { private Customer customer; private String description; public String getDescription() { return description; } public Customer getCustomer() { return customer; } public String getCustomerName() { return customer.getName(); } } class OrderPrinter { private order Order; public void printOrder() { System.out.println("Order details: " + order.getDescription() + " by user " + order.getCustomerName()); } }
This code is better and does not violate the law of Demeter because:
- The
printOrder
method of theOrderPrinter
class only accesses methods on its ‘friend’ (theOrder
class - The
getCustomerName
method also only accesses the method of its ‘friend’ (thecustomer
class)
Conclusion
The law of Demeter is a software design principle saying that an object should only interact with its immediate neighbors. In other words, an object should not reach out to other objects or services to perform actions on their behalf. It is also called as the “principle of least knowledge” because it encourages objects to only communicate with other objects that they have a direct, immediate relationship with.
I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.