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.