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.

Fixing the Violation

Fixing the violation is simple. We need to move the knowledge of the mechanics of the moon rover to a more suitable place. The obvious candidate is the MoonRover class. We can create two new methods within the MoonRover class that control the motors. One will allow forwards movement by a specific number of centimetres, with a negative value indicating that the rover should reverse. The second method will control rotation by a number of degrees with positive values indicating clockwise rotation and negative values being anticlockwise. As a side-effect of the change, we are able to make the Motor fields private, improving encapsulation.

The updated code for the MoonRover class is as follows. Note that both methods only call members of direct components of the class, so are in accordance with the Law of Demeter.

public class MoonRover
{
    private Motor _rotationMotor = new Motor("Rotation");
    private Motor _movementMotor = new Motor("Movement");

    public void MoveForward(int cm)
    {
        if (cm > 0)
            _movementMotor.StepClockwise(cm * 5);
        else
            _movementMotor.StepAnticlockwise(cm * -5);
    }

    public void RotateClockwise(int degrees)
    {
        if (degrees > 0)
            _rotationMotor.StepClockwise(degrees * 10);
        else
            _rotationMotor.StepAnticlockwise(degrees * -10);
    }
}

We now need to modify the MoonRoverRemoteController class as it can no longer access the robot's motors directly. We simply replace the calls to the motor methods with calls to the MoonRover's methods:

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

    public void PressLeftButton()
    {
        _rover.RotateClockwise(-1);
    }

    public void PressRightButton()
    {
        _rover.RotateClockwise(1);
    }

    public void PressForwardButton()
    {
        _rover.MoveForward(1);
    }

    public void PressBackwardButton()
    {
        _rover.MoveForward(-1);
    }
}

Now that the rover controls its own motors and the control unit only talks to the moon rover software the Law of Demeter is met. We've also added extra flexibility to the code. If the stepper motors in the physical unit are replaced with more accurate, or less costly, versions, we can easily change the multipliers in the MoveForward and RotateClockwise methods to compensate. If the propulsion system is completely changed, we only need modify these two methods to work with the new hardware; the MoonRoverRemoteController class and any other controllers will not need updating.

When not to Apply the Law

It is a good idea to follow the rules of the Law of Demeter when developing your classes. However, there are some situations where little benefit, if any, is gained and where applying the law leads to lots of unnecessary wrapper code that avoids coupling where coupling is appropriate. A good example of this is where you use classes for holding data objects or for data binding.

If you have created a class to hold customer details and another for supplier information, both types of contact may include an address. Rather than define the address properties for customers and suppliers individually, it make more sense to create an Address class containing standard address data and add an Address property to all classes that require it.

Once you have this structure in place, you may wish to obtain the first address line for a contact using the syntax customer.Address.AddressLine1. Although this could be seen as being in violation of the Law of Demeter, it would still be a sensible design.

19 February 2012