The Law of Demeter

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 almost 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 lament 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:

  • Objects in class parameter
  • The object in function parameter
  • The object in class members
  • 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:

objectA.getObjectB().doSomething();

or even worse, this:

objectA.getObjectB().getObjectC().doSomething();

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:

def wrongUsage(translation: Translation, s: String): String = {
      translation.dictionary.translate(s"$name$s")
    }

Translation class looks like:

class Translation(val dictionary: Dictionary)  {
  def translate(s: String): String =
    dictionary.translate(s)
}

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.

sealed trait Dictionary {
  def language: Language
  def translate(s: String): String
}

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.

/**Dictionary v2.0*/
sealed trait Dictionary {
  def language: Language
  def translate(translationString: TranslationString): String
}

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:

/**Translation v2.0 (using Dictionary v2.0)*/
class Translation(val dictionary: Dictionary)  {
  def translate(s: String): String ={
    val translationString = TranslationString(s, "someMetadata")
    dictionary.translate(translationString)
  }
}

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

/**using Translation v2.0 */
def wrongUsage(translation: Translation, s: String): String = {
translation.dictionary.translate(s"$name$s")
//ERROR: Type mismatch, expected: TranslationString, actual: String
}

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

/**works same with Translation and Translation v2.0*/
def rightUsage(translation: Translation, s: String): String = {
      translation.translate(s"$name$s")
    }

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 it 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

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s