Apply Law of Demeter: Controlling Navigation Code

Originally written by Patrick Steyaert; extended by Karl Lieberherr

Intent

Control navigation code responsible for duplication of structural information already contained in the class diagram.
Control number of classes whose services are used in a given method.

Problem

Class diagrams summarize the fundamental structure of an OO program. A common problem in object-oriented programming is that the structural information in the class diagram is duplicated over and over in the method bodies (Structure Duplication Problem).

When we focus on one method of a class, we might be overwhelmed by the number of distinct classes whose services are used in that method. We call this the Method Information Overload Problem.

The  Law of Demeter has been devised to control both the Structure Duplication Problem and the Method Information Overload Problem. The General Formulation of the Law of Demeter addresses directly the overload problem: "Each unit should have only limited knowledge about other units: only units "closely" related to the current unit." The idea is that the number of closely related units should be relatively small compared to the total number of units in the system. In the application to OO, the units are methods.

The following pictures use a very simple example to show violations of the Law of Demeter graphically.

 Law of Demeter violation (class diagram)
 Law of Demeter violation source code (Java)
 Follow Law of Demeter (class diagram) Two small methods foo2() and bar2() are introduced.

Symptoms

Solution

There are two solutions to control the navigation code:

Introduce small methods in the navigation path

See Patrick's Address example and examples in the original Law of Demeter papers.

Introduce traversal objects that are defined by a higher-level navigation language

A traversal object is an object of class TraversalGraph that has a method traverse(Object, Visitor) where the first argument defines the object to be traversed and the second argument defines a Visitor object that specifies what needs to be done in addition to the traversal. The crux of the idea is that TraversalGraph has a constructor that accepts as String argument a high-level navigation language (similar to the XML navigation language XPath) to specify traversals. A simple constructor call would be TraversalGraph("from BusRoute via BusStop to Person") that defines navigation through a bus route object.

Suppose we wish to implement a Person counting method for class BusRoute. We parameterize the counting operation by a traversal graph object.

class BusRoute{
  public int countPerson(TraversalGraph tg){ // traversal/visitor weaving
       tg.traverse(this, new Visitor(){
         int r;
         public void before(Person host){ r++; }
         public void start() { r = 0;}
       }
  }
}

If we wish to count the number of persons riding in buses we call: aBusroute.countPerson(new TraversalGraph("via Bus to Person")). If we wish to count the number of persons waiting at bus stops we call: aBusroute.countPerson(new TraversalGraph("via BusStop to Person")). Note how much navigation code we have eliminated if we use the code in the following two class diagrams:BusRoute  BusRoute with villages .

Class TraversalGraph can be implemented from scratch or down-loaded from the Adaptive Programming library page available at the Demeter home page.

When a violation of the Law of Demeter is detected we would like to know which solution to apply. The small methods solution is convenient when the class diagram is fairly stable or when a fast implementation is needed. The traversal graph solution is convenient if the class diagram is changing frequently and navigation speed is not very important. Note that the traversal graph is interpreted at runtime.