Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
Table of contents :
Introduction
Programming principles are defined in order to help developers write clean, easy to maintain and test code.
The Law of Demeter is no outlier to this definition, having been established in order to decrease coupling.
What is coupling?
Coupling is the degree of dependence modules have on each other. There can be two types of modules: loosely coupled and tightly coupled.
It is considered a good practice to write loosely coupled modules. Why? Let's talk about why we shouldn't do the opposite first.
Tightly coupled instances are deemed unsuitable because of their high level of dependence on each other, which makes them hard to modify.
Say that after you run a couple of tests on your application, you realize that something is fundamentally wrong with one of your classes. But that class is dependent on another one, which you have to change as well in order to correct your mistake -- and this situation could just go on and on, depending on how tightly coupled your classes are.
You can see how that could get rather inconvenient, right? Loosely coupled modules suddenly sound perfect.
So does this mean we shouldn't make anything dependent on something else?
No, not exactly. Having strong relationships between the functionalities inside a module is actually considered a good thing. This concept is called cohesion.
Coupling VS Cohesion
Let's give a quick example to make this extremely clear. The files are going to have the .jsx extension, which is specific to React, but don't worry, you don't need to know React in order to understand it.
So, we want to create three pages, each of which has a header, main section and a footer. Above, you can find two different approaches to this task. One of them is high cohesion and loosely coupled, while the other is low cohesion and tightly coupled.
Can you guess which is which?
...
...
...
...
...
The answer is simple: the first is low cohesion and tightly coupled, while the second is high cohesion and loosely coupled.
Explanation:
In the first approach, we have one instance (page), dependent on multiple folders. I.e in order to create a single page, you would have to make all 3 folders depend on each other, which is why that approach is called tightly coupled. The cohesion is low because the overall 'inside' functionalities of a page (header, main section, footer) aren't dependent on each other.
In the second approach, any given page can be defined just from its own folder. It doesn't depend on the rest of the folders, which is why we call this approach loosely coupled. The cohesion is high, because the functionalities inside a page folder depend on each other.
The first approach is considered bad practice, while the second is deemed the best. You can probably see how the code in the second approach would be easier to maintain and change, or be decipherable by anyone, even if they aren't familiar with your code.
Let's see how the Law of Demeter can help us lean towards the second approach and write great code!
Law of Demeter
If you look up this principle's definition up anywhere, you will probably find a variant of the following:
The Law of Demeter is an Object Oriented Programming principle which states that a unit should only have access to their immediate units.
Abstract example
Let's take an abstract example to try and demistify this phrase. Say that we had three objects, X, Y and Z. If we take a look at the rule, and at those three objects, we can try to guess what it means.
It's like drawing a vertical wall right through the middle object. If objects should only have access to their most immediate units, or, as it has otherwise been stated, 'talk to their most immediate friends', that means that X can't access Z, nor the other way around.
Code example
If you still didn't wrap your head around it, that's okay. I know it took me a couple tries. Let's try a code example.
Imagine a fruit example.
Say we had a FruitBasket class, which is keeping a Fruits object and whatever else properties a basket might have (color, material etc) inside:
class FruitBasket {
constructor(color) {
this.fruits = new Fruits();
this.color = color;
}
}
Then, we need to define the Fruits object, maybe with a few Fruits inside of it:
class Fruits {
constructor() {
this.fruits = [
this.fruit1 = new Fruit(banana, true),
this.fruit2 = new Fruit(apple, false),
this.fruit3 = new Fruit(orange, true),
]
}
}
At last, let's define the Fruit object:
class Fruit {
constructor(name, isRipe) {
this.name = name;
this.isRipe = isRipe;
}
}
What does it mean to invalidate the Law of Demeter?
Let's say that our goal is to get the number of the ripe fruits we have in the basket.
If we weren't to think about the Law of Demeter at all, we would probably go ahead and define a method directly on the FruitBasket class, possibly like so:
getAllRipeFruits() {
let count = 0;
this.fruits.filter(fruit => {
if (fruit.isRipe)
count++;
})
return count;
}
If we think back on our abstract example, though, we could identify these three classes as X, Y, Z. Therefore, X could be the FruitBasket, Y, the Fruits, and Z, the individual Fruit class.
Looking back on this, we could see that X actually depends on Z, because we are accessing the Fruit class from the FruitBasket class.
That means we are breaking the Law of Demeter.
How do we abide by the Law of Demeter?
Instead of calling the method from the FruitBasket class, we could delegate it to the Fruits class using the same method. Now, if we still need it in the FruitsBasket class, we could get the answer directly from the Fruits class. Talking abstractly, this would be Y accessing Z, and then X accessing Y. Totally valid according to the standards of the Law of Demeter!
Controversy
The usage of this law is rather controverisal in the coding community, and you might find a lot of differing opinions. There are valid arguments on both sides:
People that consider it a good practice argue that it is a great method of reducing coupling, while people that are against it usually reason that, if this law is used, the middle interface (i.e Y), gets diluted in the proccess, since material that doesn't really belong there but is needed by another instance (X, in our example) is defined inside of it.
Conclusion
In conclusion of this article at OpenGenus, the Law of Demeter, or 'don't talk to strangers' is a principle in Object Oriented Programming known to help developers reduce coupling and, therefore, write easy to maintain code. It might be detrimental sometimes, due to flooding of the 'facade' instance's interface.
I think that the Law of Demeter is a good practice, but that it should be used as a guideline, rather than as a rule. If you intend on breaking it, do it conscientiously.