The Law of Demeter

Knoldus Inc.
Knoldus - Technical Insights
3 min readJun 26, 2018

You’ll often get to hear from good programmers about having “loosely coupled” classes.
What do they mean by saying that?
Let’s understand this first before jumping onto the Law of Demeter.

Loosely Coupled

In object-oriented design, the amount of coupling refers to how much the design of one class depends on the design of another class. In other words, how often do changes in class A force related changes in class B? Tight coupling means the two classes often change together, loose coupling means they are mostly independent. In general, loose coupling is recommended because it’s easier to test and maintain.

Let’s move back to the Law.

The Law of Demeter

In layman’s terms, this law says what we are told since our childhood — “Don’t talk to Strangers”.

Talking in technical terms,

It says our function should only access the classes/objects that it has direct access to which are:

i. Objects in class parameter
ii. The object in function parameter
iii. The object in class members
iv. Objects created inside the function body.

Law_of_Demeter_illustrated

A can talk to B since A is a friend of B. So, A can send and receive messages from B. By messages, we mean accessing its objects. But C is a stranger to A. So, any conversation between A and C is a clear violation of this law.

In short, the Law of Demeter aims to keep you from doing things like this:

[code language=”Scala”]
objectA.getObjectB().doSomething();
[/code]
or even worse, this:

[code language=”Scala”]
objectA.getObjectB().getObjectC().doSomething();
[/code]

The intent of this “law” is to prevent you from reaching into an object to gain access to a third object’s methods.

Let’s understand the Law of Demeter with an example:

[code language=”Scala”]
def wrongUsage(translation: Translation, s: String): String = {
translation.dictionary.translate(s”$name$s”)
}

[/code]

Translation class looks like:

[code language=”Scala”]
class Translation(val dictionary: Dictionary) {
def translate(s: String): String =
dictionary.translate(s)
}
[/code]

As you can see that the Translation class has a class parameter “dictionary” of type Dictionary. In the wrongUsage() method through the translation object we are calling the translate method of the dictionary object which is foreign to our wrongUsage() method.

[code language=”Scala”]
sealed trait Dictionary {
def language: Language
def translate(s: String): String
}
[/code]

Clearly, this shouldn’t happen.
Before going onto how it should’ve been done, let’s see why LoD restricts us from doing this blunder.

Till now we have seen that this translate object is from some third party library (which we are using) is further using some other library Dictionary. So, this Dictionary class is foreign to us. Right?
No surprise that this library might change its method in further releases.
Say, for example, it changes the method parameter. Earlier it used to take a String parameter (see the above snippet) and now it takes some TranslationString object.

[code language=”Scala”]
/**Dictionary v2.0*/
sealed trait Dictionary {
def language: Language
def translate(translationString: TranslationString): String
}
[/code]

So, in this case, will our code still be working fine?

The answer is obvious, a big NO!

Though Translation class has handled the changes:

[code language=”Scala”]
/**Translation v2.0*/
class Translation(val dictionary: Dictionary) {
def translate(s: String): String ={
val translationString = TranslationString(s, “someMetadata”)
dictionary.translate(translationString)
}
}
[/code]

and since we are trying to be friendly with the foreign library, so this impacts our code:

[code language=”Scala”]
def wrongUsage(translation: Translation, s: String): String = {
translation.dictionary.translate(s”$name$s”)
//ERROR: Type mismatch, expected: TranslationString, actual: String
}
[/code]

Time to see what should be the best way to do this?

[code language=”Scala”]
def rightUsage(translation: Translation, s: String): String = {
translation.translate(s”$name$s”)
}
[/code]

Things make sense now! We have to just call the translate method of Translation class, how translation will deal with the foreign library we shouldn’t be concern about that.

If you’re still not clear with this, you can check its complete implementation from here or you can ask in the comments.

You can further read about Clean Code from this blog.

Hope it helped! :)

References:
1. https://stackoverflow.com/questions/2832017/what-is-the-difference-between-loose-coupling-and-tight-coupling-in-the-object-o
2. https://alvinalexander.com/java/java-law-of-demeter-java-examples

knoldus-advt-sticker

--

--

Knoldus Inc.
Knoldus - Technical Insights

Group of smart Engineers with a Product mindset who partner with your business to drive competitive advantage | www.knoldus.com