Law of Demeter
(Created the page with a basic explanation, including consequences and a solution) |
(Added an example) |
||
Line 20: | Line 20: | ||
=== Example === | === 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: | |
+ | |||
+ | [[Image: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: | ||
+ | |||
+ | [[Image:demeter2.png]] |
Revision as of 00:27, 3 August 2008
The Law of Demeter says that an object cannot request services from an object via a different object.
"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().
Consequences
A violation of the Law of Demeter means that the caller object is dependant 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. 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: