Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obey Law of Demeter?

Tags:

Any time I see articles about Law of Demeter the author never seems to give a solid example of how to obey this law. They all explain what it is and show an example of breaking the law but that is easy.

There is probably lots of ways to obey this law (good design and planning being one) but in very simple terms would this be a way to obey it?

Let's say I have a class with these properties:

public class Band {      private Singer singer;     private Drummer drummer;     private Guitarist guitarist; } 

I am somewhere in the program and I have an instance of this Band class and I want the guitarists name, what I usually see is something like:

guitaristName = band.getGuitarist().getName(); 

That one does not seem too bad as it is not going too deep in the chain but is Law of Demeter saying that maybe it should be done this way:

guitaristName = band.getGuitaristName(); 

and my Band class has a method:

public String getGuitaristName() {     return guitarist.getName(); } 

Is this how you are supposed to obey the law?

Thanks.

like image 714
ibanore Avatar asked Jun 30 '13 17:06

ibanore


People also ask

How do I follow the Law of Demeter?

Understanding the Law of Demeter principle The Law of Demeter principle states that a module should not have the knowledge on the inner details of the objects it manipulates. In other words, a software component or an object should not have the knowledge of the internal working of other objects or components.

What is the Law of Demeter trying to prevent?

The Law of Demeter asks us to minimize coupling between classes and avoid reaching out to the third object in order in order to make refactoring and developing new features easily.

What is a result of adhering to the Law of Demeter principle?

High Cohesion (HC): Adhering to the Law of Demeter often results in additional methods that mirror methods of aggregated objects. As these objects have other responsibilities, the additional methods have fewer commonalities with the “real” methods of the class, which results in a lower cohesion.


1 Answers

I think the idea of the law is, as Dancrumb says above, to ensure that people are accessing objects at the appropriate level.

Imagine that our Band class models the front desk of the band's offices. It's job is to act as a PA to the band members & deal with anyone who wants to interact with the band.

Now let's say we had a tour promoter from a PR company who wants to put together some PR material for their next tour. We could model him with a class:

class TourPromoter {    public String makePosterText(Band band) {     String guitaristsName =  band.getGuitarist().getName();     String drummersName = band.getDrummer().getName();     String singersName = band.getSinger().getName();     StringBuilder posterText = new StringBuilder();      posterText.append(band.getName()     posterText.append(" featuring: ");     posterText.append(guitaristsName);     posterText.append(", ");     posterText.append(singersName);     posterText.append(", ")     posterText.append(drummersName);     posterText.append(", ")     posterText.append("Tickets £50.");      return posterText.toString();   }  } 

In real life, this is the equivalent of the tour promoter ringing up the office & saying:

  • Tour Promoter: Can I speak to your guitarist?

  • Receptionist: OK, I'll get him for you.

  • Guitarist: Hello, this is the guitarist

  • Tour Promter: Hi, I'm putting together your latest poster. Just wanted to check your name?

  • Guitarist: It's Jimmy Page

  • Tour Promoter: Great, thanks. Oh, could you get me your drummer?…

Suffice it to say that the PA would get fired pretty quickly. Most reasonable people would ask "Couldn't you have handled that phone call for us?"

We could have a getGuitaristsName() method, which would technically be honouring the Law of Demeter, but we're still asking our TourPromoter class to remember details about the band — i.e. that they have a guitarist — whereas this information should really belong to the band itself.

To make sure we're introducing methods in a sensible way, we need to look at what the tour promoter is actually looking for — i.e. the names of all the band members. If we model that method in code, it gives us greater flexibility to make changes to the Band later on, without having to even touch TourPromoter:

public class Band {     private Singer singer;     private Drummer drummer;     private Guitarist guitarist;      public String[] getMembers() {         return {singer.getName(), drummer.getName(), guitarist.getName()};     }   }  public class TourPromoter {     public String makePosterText(Band band) {         StringBuilder posterText = new StringBuilder();          posterText.append(band.getName());         posterText.append(" featuring: ");          for(String member: band.getMembers()) {             posterText.append(member);             posterText.append(", ");         }         posterText.append("Tickets: £50");          return posterText.toString();     }     } 

If we now add a Bassist or KeyboardPlayer, only the Band class needs to know the difference & the Tour Promoter doesn't need to change. This means that we're now also honouring the Single Responsibility Principle too — i.e. our makePosterText() method only needs to change if we change our poster format, not if the band changes.

I don't think the Law of Demeter will tell you which method you need to pull out in order to meet the principle in the best way (e.g. getMembers() rather than getGuitaristsName() above) & in that way, I think you are right — it does show you when things are broken, but not necessarily how to fix them. Having the LoD in mind though, means that you keep an eye out for violations that can then be fixed through a combination of other design principles, like SRP.

like image 78
anotherdave Avatar answered Sep 18 '22 15:09

anotherdave