Law of Demeter
(Added an example) |
Jenny Harlow (Talk | contribs) m (add link to Hide Delegate) |
||
(10 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
− | The Law of Demeter says that an object cannot request services from an object via a different object. | + | 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: | "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: | ||
Line 6: | Line 6: | ||
# M's parameters | # M's parameters | ||
# any objects created/instantiated within M | # any objects created/instantiated within M | ||
− | # O's direct component objects" -- | + | # O's direct component objects" --[http://en.wikipedia.org/wiki/Law_of_Demeter 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(). | 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(). | ||
Line 12: | Line 12: | ||
=== Consequences === | === Consequences === | ||
− | A violation of the Law of Demeter means that the caller object is | + | 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 === | === 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 27: | Line 27: | ||
[[Image:demeter2.png]] | [[Image:demeter2.png]] | ||
+ | |||
+ | === Example 2 === | ||
+ | |||
+ | This first design does not adhere to the Law of Demeter. | ||
+ | |||
+ | [[Image: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. | ||
+ | |||
+ | [[Image: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== | ||
+ | * [[Tell, don't ask]] | ||
+ | * [[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:
- O itself
- M's parameters
- any objects created/instantiated within M
- 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:
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:
Example 2
This first design does not adhere to the Law of Demeter.
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.
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.