Search
Search

# Testable Code : Law of Demeter

### Data/Object Antipodality

Before we delve into the Law of Demeter, it is important to understand the difference between a data structure and an object. This is a basic understand that most programmers overlook.

A data structure is a container of data which it expose to the outside world directly. It does not have any functions that act on the data. The consumers of this data structure can process the data any which way they please. An object, on the other hand, hides the data that it contains behind meaningful abstractions and only exposes functions that act on the data.

Let us take a popular example to illustrate this difference:

3D Shape implemented as a Data Structure
`class Cube {`
`    public int side;`
`}`
`class Cone {`
`    public int radius;`
`    public int height;`
`}`
`class 3DShape {`
`    public int getVolume (Object shape) {`
`        if(shape instanceof Cube) {`
`            Cube cube = (Cube) shape;`
`            return cube.side * cube.side * cube.side;`
`        }`
`        if(shape instanceof Cone) {`
`            Cone cone = (Cone) shape;`
`            return 3 * cone.radius * cone.radius * cone.height;`
`        }`
`        return 0;`
`    }`
`}`
3D Shape implemented as an Object
`abstract class 3DShape {`
`    public int getVolume();`
`}`
`class Cube extends 3DShape {`
`    private int side;`
`    public int getVolume() {`
`        return side * side * side;`
`    }`
`}`
`class Cone extends 3DShape {`
`    private int radius;`
`    private int height;`
`    public int getVolume() {`
`        return 3 * radius * radius * height;`
`    }`
`}`

If you have been brought up on Object Oriented programming, you would be laughing at the naivety of the first implementation.

Let us examine both the above implementations. In the first implementation, if you can add a new function (say, getSurfaceArea()) and you would need to change only the 3DShape class. The Cube and Cone classes would remain exactly the same. In the second implementation, any new method in the second implementation means changing all the three classes. Similarly, adding a new shape in the first implementation (say, a Cuboid) would mean adding an additional if block. In the second implementation, none of the existing functions are changed.

This can be summarized as follows:

Data Structures make it easy to add new functions without changing existing data structures whereas Objects make it easier to add new Objects without changing existing functions.

So, what is easy for data structures is hard for objects and vice-versa. Hence, it is extremely difficult to combine these attributes in one object. This is an important anti-symmetry that most programmers fail to understand.

### Law of Demeter

The Law of Demeter states the following:

A method f of a class C should only call the methods of these:

• C
• an object created by f
• an object passed as an argument to f
• an object created in an instance variable of C

Look at the piece of code below:

`CComp cc = context.getExplorer().getComponentController().getClientComponent();`

These ‘train wrecks’ are one of the first signs of a violation of the law of demeter. Here, it is very difficult to ascertain whether ‘context‘ is an object or a data structure. It has mixed responsibilities and this becomes very difficult to test. Breaking this up into various statements will not fix the inherent problem. Nor will the following:

`context.getClientComponentFromControllerOfExplorer();`

This will result in a flood of functions in the context class.

The way to fix is to determine why the client component is required. Let us assume the following piece of code follows the one above:

`cc.setName("My Client");`

Then, we could refactor the above lines as follows:

`context.setClientComponentName("My Client");`

This clearly states that context is an object with functions that act on its data rather than it being a data structure that lets other objects act on its data.

In conclusion, it is important to follow the law of demeter and call only ‘friends’. This makes code very easy to test, verify and narrow down the source of errors.