Law of Demeter

From CSSEMediaWiki
(Difference between revisions)
Jump to: navigation, search
m
m (add link to Hide Delegate)
 
(One intermediate revision by one user not shown)
Line 16: Line 16:
 
=== Solution ===
 
=== Solution ===
  
The best solution is to write wrapper methods in the class to allow callers to ask that class for information about objects it contains. Unfortunately this may mean the class presents a very large public interface.
+
The best solution is to write wrapper methods in the class to allow callers to ask that class for information about objects it contains (for example, see Martin Fowler's [[Hide Delegate]] refactoring). Unfortunately this may mean the class presents a very large public interface.
  
 
=== Example ===
 
=== Example ===
Line 66: Line 66:
 
is ok according to the Law of Demeter. If instead of instantiating B directly, we use a factory of type A to instantiate B, we get:
 
is ok according to the Law of Demeter. If instead of instantiating B directly, we use a factory of type A to instantiate B, we get:
  
void doSomething(A a) {
+
void doSomething(A a) {
 
   B b= a.makeMeaB();
 
   B b= a.makeMeaB();
 
   b.callSomething()
 
   b.callSomething()
Line 73: Line 73:
 
This is not ok according to the Law of Demeter. If we combine the second and third line of the code we get a definite violation of the Law of Demeter:
 
This is not ok according to the Law of Demeter. If we combine the second and third line of the code we get a definite violation of the Law of Demeter:
  
void doSomething(A a) {
+
void doSomething(A a) {
 
     a.makeMeaB().callSomething();
 
     a.makeMeaB().callSomething();
 
  }
 
  }
Line 82: Line 82:
 
* [[Tell, don't ask]]
 
* [[Tell, don't ask]]
 
* [[Message chain smell]]
 
* [[Message chain smell]]
 +
* [[Hide Delegate]]

Latest revision as of 06:34, 19 October 2010

The Law of Demeter, or Principal of Least Knowledge, says that an object cannot request services from an object via a different object. Objects in a design which obeys the Law of Demeter can be seen to "only talk to their immediate friends".

"More formally, the Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:

  1. O itself
  2. M's parameters
  3. any objects created/instantiated within M
  4. O's direct component objects" --Wikipedia

A common (but certainly not the only) indicator of a violation of the law in some languages is more than one dot in a line of code, for example man.getTrousers().checkPocketContents().

Contents

Consequences

A violation of the Law of Demeter means that the caller object is dependent on the internal structure of the object it accesses. In the above example, if the Trousers class were to change (to say, Shorts, or perhaps a more abstract piece of clothing) the original caller would need to be updated.

Solution

The best solution is to write wrapper methods in the class to allow callers to ask that class for information about objects it contains (for example, see Martin Fowler's Hide Delegate refactoring). Unfortunately this may mean the class presents a very large public interface.

Example

Consider a simple graphics example. A 3D scene contains a number of point clouds (amongst other things which we'll ignore). Each PointCloud consists of a number of vertices. Here is the class diagram initially:

Demeter.png

In this design, if a Scene requires a PointCloud to be displayed it will need to get the list of vertices from the PointCloud first. Then it can display each vertex in turn. In this case, it should seem fairly obvious that something is wrong. In fact, the Law of Demeter has been violated, since the Scene obtains vertices through the PointCloud and calls their method. If the PointCloud were to change how it is composed, then Scene will most likely need to be modified (unless getVertices is modified to create a list from the new representation, but this could be messy). The solution in this case is fairly simple. PointCloud requires a display() method which displays each of its vertices. Scene can then simply call this method. The (slightly) modified version is shown below:

Demeter2.png

Example 2

This first design does not adhere to the Law of Demeter.

Carengine1.jpg

This is because to start the car you would have to execute the following line of code...

  car.getEngine().start()

The Law of Demeter states that generally more than one dot in a line of code is a sign that the law has been broken.


This design adheres to the Law of Demeter because the Car is handling the starting of itself (in the start() method) instead us having to specifically get the engine and tell it to start.

Carengine2.jpg


start()
{
    engine.start();
}

Criticisms

The Law of Demeter has been widely criticized as being too restrictive and invalid. Tell, don't ask was instead proposed as a less strict and less restrictive version.

Some people on Ward's wiki claim that the Law of Demeter is invalid because there are refactorings that transform code that breaks the Law of Demeter into code that doesn't break it but does not change the Information hiding of the program and preserves all of the coupling and dependencies of the program. Therefore, they argue that the Law of Demeter doesn't really distinguish between good and bad designs.

This is the example they use to support their reasoning. This code:

void doSomething() {
  B b= new B();
  b.callSomething();
}

is ok according to the Law of Demeter. If instead of instantiating B directly, we use a factory of type A to instantiate B, we get:

void doSomething(A a) {
  B b= a.makeMeaB();
  b.callSomething()
}

This is not ok according to the Law of Demeter. If we combine the second and third line of the code we get a definite violation of the Law of Demeter:

void doSomething(A a) {
   a.makeMeaB().callSomething();
}

As a result, they argue that the Law of Demeter does not allow some perfectly good designs.

See also

Personal tools