Understanding and Applying the Law of Demeter in Java

The Law of Demeter (LoD), or the principle of least knowledge, is a software engineering design guideline that was formulated at Northeastern University towards the end of the 1980s. It primarily serves to promote loose coupling among software modules, thereby enhancing the maintainability and understandability of a software system.

The central tenet of the Law of Demeter is straightforward – an object should limit its interactions to a close circle of related objects or, in other words, its “immediate neighbors”. This principle can be summarized as “Only talk to your immediate friends”.

In the context of an object-oriented language like Java, the Law of Demeter can be applied to guide the interactions between objects and their methods. Let’s delve deeper into this with an illustrative example.

Consider two classes: Document and Printer. A Document contains DocumentDetails such as content, author, creation date, etc.

In the violation of the Law of Demeter, we might have:

public class BadPrinter {
    private Document document;
    
    public BadPrinter(Document document) {
        this.document = document;
    }
    
    public void print() {
        String content = document.getDetails().getContent();
        System.out.println(content);
    }
}

The print() method in the BadPrinter class is violating the Law of Demeter by invoking a method (getContent()) on an object (DocumentDetails) that is retrieved from another object’s (Document) method (getDetails()).

According to the Law of Demeter, the BadPrinter should only communicate directly with the Document, not with the DocumentDetails. The BadPrinter class is dealing with classes that it should not be aware of, causing a higher degree of coupling, which in turn makes the code more brittle and less flexible to changes.

A more Demeter-compliant version might look like:

public class GoodPrinter {
    private Document document;
    
    public GoodPrinter(Document document) {
        this.document = document;
    }
    
    public void print() {
        String content = document.getContent();
        System.out.println(content);
    }
}

class Document {
    private DocumentDetails details;

    public String getContent() {
        return details.getContent();
    }
}

In this case, the GoodPrinter class directly calls a method (getContent()) on the Document object, which is its immediate neighbor. It is not aware of any further classes or dependencies, like DocumentDetails. The method getContent() is added to the Document class to handle the interaction with the DocumentDetails object.

This version adheres to the Law of Demeter, resulting in a more loosely coupled system where GoodPrinter does not need to know about any class beyond Document.

Applying the Law of Demeter improves the modularity and robustness of software systems by reducing the dependency between classes. It allows objects to remain as isolated as possible, making them more reusable and easier to maintain. However, as with all design principles, it should not be applied blindly but should be considered in light of the specific requirements and context of the project.

On my Twitter and Instagram accounts, I frequently share my programming journey and development experiences.

Thanks for reading 🙂