The Law of Demeter might be one of the most well-defined, useful, and concisely written rules of Object-Oriented software development ever. It might also be one of the most often ignored things in our profession — other than deadlines.

Let’s take a deep dive into what it says, what it actually means, and how to obey it in letter and spirit.

Why Should We Obey the Law of Demeter?

There are well-known abstract concepts in Object-Oriented programming, like encapsulation, cohesion, and coupling, that could be theoretically used to generate clear designs and good code. While these are all very important concepts, they are just not pragmatic enough to be directly useful for development. One has to interpret these concepts, and with that, they become somewhat subjective and start to depend on people’s experience and knowledge.

The genius of the Law of Demeter comes from the succinct and exact definition, which allows for a direct application when writing code, while at the same time almost automatically guaranteeing proper encapsulation, cohesion, and loose coupling. The authors of the Law managed to take these abstract concepts and distil the essence of them into a clear set of rules that are universally applicable to Object-Oriented code.

So What Does It Say?

The Law, in its original form, is stated this way:

For all classes C, and for all methods M attached to C, all objects to which M sends a message must be

M’s argument objects, including the self object or

The instance variable objects of C

(Object created by M, or by functions or methods which M calls, and objects in global variables are considered as arguments of M.)

In the early days of Object-Orientation, objects were supposed to “send messages” to each other. That is how they communicated. So the term “objects to which M sends a message” roughly translates to “objects used by M,” or in a more practical definition “objects on which M calls a method on.”

You might have noticed that there are some very important additional points made in parentheses after the two rules. They seem like clarifications mentioned just in passing, but they are actually additional rules. So let’s reformulate the whole Law so all points stand independently:

For all classes C, and for all methods M attached to C, all objects to which M sends a message must be:

self (this in Java)

M’s argument objects

Instance variable objects of C

Objects created by M, or by functions or methods which M calls

Objects in global variables (static fields in Java)

What Does It Mean?

Well, the law formulates what we are allowed to do in any given method M. So, let’s work backward and find out what it is exactly what this law prohibits.

Rule #4 states, that all objects created during the call to M, either directly or indirectly, are allowed. So the prohibition must be among objects that already existed when the call began.

These already existing objects must have a reference to them, otherwise, nobody would be able to access them. Therefore these objects must be referenced from fields (variables) of other objects. Rule #5 allows global objects, so that leaves us with objects in instance variables.

Rules #1, #2, and #3 further allows “self”, M’s parameters and all objects in instance variables of C.

That means that the Law prohibits “sending a message” to any already existing object that is held in instance variables of other classes, unless it is also held by our class or passed to us as method parameters.

This is a violation of the Law of Demeter. The method received the parameter person, so all method calls on this object are allowed. However, calling any methods (in this case getBytes()) on the object returned by either getName() or getPhoto() is not allowed. Assuming standard getters, these objects are already existing objects in other objects’ instance variables, therefore they are exactly the kind of objects this method should not have access to.

Chain Calls

Some explanations of the Law concentrate on so-called “chain calls”, that is, expressions which contain multiple dereferencings. Or stated plainly, multiple “dots”, like this:

car.getOwner().getAddress().getStreet();

This is almost certainly a violation of the Law, since all those objects (owner, address) are presumably already-existing instance variable values, to which the Law prohibits access.

However, it is not the chain-calling that makes the above a violation, but the access to certain objects. The following “refactored” code still violates the Law:

As above, the objects in owner, ownerAddress, and ownerStreet are still not covered by any of the rules, therefore no methods should be called on them.

Fluent APIs

Some interpretations of the Law argue that since chain-calls are not allowed, fluent APIs are also forbidden. Fluent APIs are created to allow syntactically easy usage of a library or set of classes. They look like this:

To determine whether such a construct is allowed, we just have to check each method call to see whether it is specifically allowed. The ReportBuilder object is created in this method right now, so the first method call withBorder(1) is on a freshly created object. This is explicitly allowed by Rule #4.

All the following method calls, including the last build() call are all using the returned objects from the previous call. What is the return value of all these methods? Well, most of the fluent APIs just return the same object over and over again. That is still covered by Rule #4 because the builder is an object that was created in this code. Some fluent APIs use immutable objects and return a new object every time. But even if this is the case, Rule #4 still applies to indirectly created objects too.

So two new methods are introduced, but there was no real structural or design change. One could argue that while the Law was technically followed, the spirit of the Law was still violated.

The structure is still visible in the method name, and we all know that the caller wants to get the street of the address of the owner of the car.

The question is: Why does the caller want that, and how does he/she even know that this information exists at this point? This is when applying the Law blends together with Object-Oriented Design. Obviously, the purpose of the Law is not to roll additional hurdles in our way and make our lives more difficult. The same way that our job is not to make sure that we technically follow all the rules without thinking about our overall design.

What the Law is quite clearing saying is that you shouldn’t access the Street in this structure. As in, you shouldn’t even know it’s there. Don’t trick the definition by introducing wrapper methods! There is a deeper design issue here that needs to be addressed (no pun intended)!

Pure “Data Structures”

In his book Clean Code, Robert C. Martin has a short section on the Law of Demeter, where he makes two interesting points. One is that perhaps by using direct access to variables, the Law could be circumvented. So instead of this...

car.getOwner().getAddress().getStreet();

...which is not acceptable, it could be transformed into the following, which complies with the Law, since it doesn’t involve method calls:

car.owner.address.street; // Using direct access to fields

There are two arguments against this line of reasoning. One is that it still just tries to work around the Law instead of heeding its advice. And the second is that direct access to fields arguably still qualifies as “sending a message,” since it is still just communication between two objects.

There is a more nuanced point made by Uncle Bob regarding the above — that the Law of Demeter should not apply to pure data structures anyway.

Pure data structures (“objects” that have no behavior, just data) are integral building blocks of a procedural, functional or a mixed paradigm approach. As such, they are of course exempt from having to comply with the Law of Demeter, which is a Law for Object-Oriented development.

Getters

Most, if not all of the negative examples for the Law of Demeter given involve “getter” methods. These are methods like this:

Is the above call even allowed? Well, technically yes. The car object is a direct parameter to the method, so I may call methods on this object.

However, let’s think about what can be done with the result of this call. The method returns an owner object, which is neither a parameter nor an object that the Garage has direct access to. Therefore there can be no further method calls on this object. Not toString(), not hashCode(), nothing!

This might be considered unexpected. So that means while calling the getter itself might be technically legal, we can’t actually use the result. It seems getter methods violate the Law of Demeter almost by design.

As previously said, this is neither a coincidence nor is it unintentional. In the Object-Oriented paradigm, objects are supposed to tell other objects what to do — delegate, instead of querying data from others and doing everything themselves.

When to Apply

There are some opinions in blog posts and other articles expressing that the Law of Demeter is less of a “law” and only a “suggestion” or a “guideline.” Or that it is fine in theory, but does not apply to certain objects, like data structures, Java Beans, entities, business objects, value objects, data transfer objects, or objects for presentation or persistence.

An Object-Oriented developer should be aware that more often than not, these opinions come from a background of different programming paradigms, in which the Law of Demeter might very well have a different weight or even interpretation than in Object-Orientation.

The Law of Demeter is the law of the land in Object-Oriented development. As the original paper itself calls it, it is the Law of Good Style. Complying with the Law technically and in spirit everywhere is the minimum required to produce proper, well designed Object-Oriented code.

Conclusion

The Law of Demeter is a very well-defined set of rules for Object-Oriented development. Following these rules in letter and spirit takes little effort if one is applying good Object-Oriented Design principles anyway.

Furthermore, it produces clear signals if the code is deviating from the Object-Oriented path, therefore it is an invaluable tool to keep our designs and code style on the right track.