I tried to find a concise explanation of the Law of Demeter, and my brain melted.
The best I could find was wikipedia's entry on law of demeter.
"More formally, the Law of Demeter for functions requires that a method called from an object may only invoke the methods of the following kinds of objects:
- itself
- its parameters
- any objects it creates/instantiates
- its direct component objects
In particular, an object should avoid invoking methods of a member object returned by another method."
There is TONS written about LoD when googled, but nothing that gave me a real "aha" feeling. It all left me wondering, is this real insight, or cargo cult programming?
Hopefully the above definition will help a bit.
thomas. | [reply] |
As I understand it, the LoD is about not spreading knowledge (about the relationship between objects) all over the place.
Let's say object A has a method foo() that does something useful. Object a (instance-of class A) has-an object b that implements the useful thing.
So the call chain is a->b->foo(). But that exposes the fact that a has-a b, when in fact that information could be private to class A. According to the LoD, the call chain would be a->foo(), and that foo() would be implemented as b->foo().
Taken to an extreme, this is the “bloated middlemen classes full of forwarding methods.” that Aristotle talks about in Re^3: Are lvalue methods (as properties) a good idea?. If large parts of the interface of B is duplicated in A, what's the point? Isn't A and B pretty tightly coupled anyway?
On the other hand... What if the call chain is a->b->c->d->foo(), and you type this monster at 108 different places in your program? Wouldn't it be a bit nicer to type a->foo() and encapsulate the knowledge of b->c->d->foo() so it doesn't break at 108 different places if any of b, c, or d changes?
This is why the LoD shouldn't be a "law" to be followed at all times, but a rather a guideline. Or as the Pragmatic guys phrased it in an article I read somewhere: The Pretty Good Idea of Demeter.
(hey, I just found it. The Art of Enbugging. It's really good and, of course, explains it a lot better than I can).
IMHO,
/J
| [reply] |
To me, the a->b->c->d->foo() example just tells me that this needs to be factored out into a routine somewhere. Putting it in a's class is not necessarily the right thing, perhaps it just needs to be in a function local to the module that uses 108 times (of course if those 108 uses are spread all over then it probably should be in a's class).
Choosing the correct class to put it in may be difficult. It may be useful to call x->b->c->d->foo() for lots of different xs that don't necessarily share a base class and adding in a mixin class to all those classes may not be not possible.
Many examples of LoD are really about removing accessors. I think it's better to replace a->mother->brother->child->foo() with a->cousin->foo(). Do not replace it with a->foo_the_cousin() because chances are you'll want to call other methods on the cousin and also because it's not much of a saving in terms of typing (in this case it's not a saving at all).
So my sugestion for a better LoD is
Consider replacing chains of accessor methods with a single method
| [reply] [d/l] [select] |
I don't think the Law of Demeter should be called a “Law”, FWIW. It should more reasonably be called a “Rule” or maybe even just “Guideline”. I've seen someone aptly describe the effect of dogmatic adherence to the LoD in large frameworks as “bloated middlemen classes full of forwarding methods.” Clearly, while tight coupling and low cohesion are undesirable, decoupling and cohesion taken to the extreme mean that a unit fulfills an infinitely narrow task with infinitely minimal communication with the rest of the world — in other words, it's useless.
In a GUI widget whose purpose is to contain other widgets, f.ex, it's fine to assume knowledge that an instance of this class will have children, and to reach for these children through the container class.
Makeshifts last the longest.
| [reply] |