BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Programming Concepts

The Law of Demeter

Coupling in object-oriented software indicates the level to which classes are reliant upon each other. A tightly coupled system is usually harder to maintain and modify than a loosely coupled one. The Law of Demeter addresses a specific coupling problem.

What is the Law of Demeter?

The Law of Demeter was first described at the Northeastern University in Boston Massachusetts in 1987. "Law" is probably too strong a word for it but it does provide a set of useful guidelines for software design. When followed, the rules reduce coupling by describing how the methods and properties of classes should communicate with each other. The law is sometimes known as the Principle of Least Knowledge.

When applied in object-oriented software, the law specifies that the methods and properties of a class must only invoke members of the following objects:

  • The object in which the method or property is declared.
  • The objects passed to the member using its parameters.
  • The objects that the method or property directly instantiates.
  • Objects that are declared within the same class as the calling method or property. These are the direct component objects of the member's containing class.
  • Global objects, though these should generally be minimised.

Violation Example

The law is easier to understand with an example. Consider the code below. Here we have a set of classes that mimic the control of a moon rover. The MoonRoverRemoteController class is the software for a control panel with buttons that move a robot forwards or backwards and rotate it clockwise or anticlockwise.

The MoonRover class includes two public fields. Each represents a motor that controls the movement and rotation of the device. The Motor class controls a stepper motor that can be rotated clockwise or anticlockwise by a precise amount, moving the rover accordingly. In the real world this class would control physical motors. For example purposes it outputs a message for each movement.

public class MoonRoverRemoteController
{
    public MoonRover _rover = new MoonRover();

    public void PressLeftButton()
    {
        _rover.RotationMotor.StepAnticlockwise(10);
    }

    public void PressRightButton()
    {
        _rover.RotationMotor.StepClockwise(10);
    }

    public void PressForwardButton()
    {
        _rover.MovementMotor.StepClockwise(5);
    }

    public void PressBackwardButton()
    {
        _rover.MovementMotor.StepAnticlockwise(5);
    }
}

public class MoonRover
{
    public Motor RotationMotor = new Motor("Rotation");
    public Motor MovementMotor = new Motor("Movement");
}

public class Motor
{
    string _motorName;

    public Motor(string motorName)
    {
        _motorName = motorName + " Motor";
    }

    public void StepClockwise(int steps)
    {
        Console.WriteLine("{0} stepped clockwise {1} steps", _motorName, steps);
    }

    public void StepAnticlockwise(int steps)
    {
        Console.WriteLine("{0} stepped anticlockwise {1} steps", _motorName, steps);
    }
}

These three classes operate the moon rover unit correctly and represent a working system. We can see this by instantiating a MoonRoverRemoteController object and pressing some buttons:

MoonRoverRemoteController controller = new MoonRoverRemoteController();
controller.PressForwardButton();
controller.PressLeftButton();

/* OUTPUT

Movement Motor stepped clockwise 5 steps
Rotation Motor stepped anticlockwise 10 steps

*/

The Violation

The violation in the above example is in the MoonRoverRemoveController class. When any button is pressed, one of the motor objects is obtained from the MoonRover object. The retrieved object's StepClockwise or StepAnticlockwise method is then called. If you refer back to the five types of objects that may be invoked, you will see that calling a method on an object that you retrieve from another is not permitted. The call in the example is not to a member of the containing class, a parameter, an object that the method has instantiated, a member of the containing class' components or a global object. It is a member of a component of one of the containing object's components. This is a subtle but important difference.

By calling the methods of the Motor class from the MoonRoverRemoteController class we have coupled these classes unnecessarily. The controller unit's software has too much knowledge of the inner workings of the moon rover. This tight coupling is damaging to the flexibility of the software. Should the moon rover be modified to use continuous tracks it may have two motors that must be co-ordinated to achieve the same forwards, backwards and rotation movements. This would require that the controller system's software be rewritten. It's possible that a technology improvement would replace the need for stepper motors entirely, causing even more problems in the controller.

19 February 2012