LawOfDemeter

Jim's Pages => Java Pages => LawOfDemeter

Defined

The "Law of Demeter" is one of those nifty guidelines for good OO code / design. Here's how it's usually written up:

A method of an object should use only the following kinds of objects:
  1. itself
  2. its parameters
  3. any objects it creates/instantiates
  4. its direct component objects

It may take a moment to see what's missing, and that's the kind of chained references or getters that we often see. Something like

myFrame.getPanelA().getWidgetX().setText("Hello");

is right out. Demeter tells you to do something more like:

myFrame.setWelcomeText("Hello");

and let the frame worry about all those other details. (Of course with MVC we'd do something completely different, but let's pretend it's ok to talk to frames like that for a minute.)

The benefit is all the goodness of encapsulation, a key part of why we love objects in the first place. The panels can change, the widgets can change, but the frame hides all that knowledge and a call to setWelcomeText still works. The downside is a number of "pass through" methods that do nothing but forward the message to the next child object. 

Like many OO guidelines, it's probably impossible and impractical to follow this one 100% of the time. The balance between spreading knowledge and adding overhead is a judgment call but I generally vote for more encapsulation until the overhead becomes too painful.

Fun With Demeter

I get a kick out of some of the parables people make up to explain Demeter. Here are some fun stories with links to the original sources. They illustrate slightly different points of view and may help you remember to examine this aspect of your designs:

Smithers!

Quoted from KnightsPrinciples

Never do any work you can get someone else to do for you:

"Excuse me Smithers. I need to know the total bills that have been paid so far this quarter. No, don’t trouble yourself. If you’ll just lend me the key to your filing cabinet I’ll go through the records myself. I’m not that familiar with your filing system, but how complicated can it be? I’ll try not to make too much of a mess."

Smithers actually understands his filing system, so he can probably do the work faster than we can, and he’s much less likely to mess everything up. In seeking to do his job for him, we’re just making things worse. They’ll get a lot worse when he switches over to that new filing system next week. We’d be far better off with the stereotypical tyrant boss.

"SMITHERS! I need the total bills that have been paid since the beginning of the quarter. No, I’m not interested in the petty details of your filing system. I want that total, and I’ll expect it on my desk within the next half millisecond."

The Paperboy and the Wallet

Quoted from the IEEE Computer Society. I like the command and query concept in the IEEE paper. The linked PDF has more detail about the paperboy among other good things.

Consider the story of “The Paperboy and the Wallet,” from our friend David Bock. Suppose the paperboy comes to your door, demanding payment for the week. You turn around, and the paperboy pulls your wallet out of your back pocket, takes the two bucks, and puts the wallet back. As absurd as that sounds, many programs are written in this style, which leaves the code open to all sorts of problems (and explains why the paper boy is now driving a Lexus).

Instead of asking for the wallet, the paperboy should instead tell the customer to pay the $2.00. Code should work the same way—we want to tell objects what to do, not ask them for their state. Adhering to this notion of “Tell, Don’t Ask” is easier if you mentally categorize each of your functions and methods as either a command or a query, and document them as such in the source code (it helps if all commands are grouped together and all queries are grouped together). A routine acting as a command will likely change the object’s state and might also return some useful value as a convenience. A query just gives you information about the object’s state—and does not modify the object’s visible state. That is, queries should be free of side effects as seen from the outside world. Now, we might want to do some precalculation or caching behind the scenes as needed, but fetching the value of x should not change the value of y.

Command-query separation keeps code shy; the caller doesn’t know too much about how its command will be performed. That means we have reduced coupling by some measure, which is a good thing. Those implementation details are free to change with less chance of affecting the caller. Because the query methods are known to be side-effect free, we can use them freely in unit tests and call them from assertions or from the debugger.

Don't Confuse Your Dog

Quoted from the Portland Pattern Repository a.k.a. The WikiWikiWeb

"If you want your dog to run, do you talk [to] your dog or to each leg? Further, should you be able to manipulate the dog's leg without it knowing about it? What if your dog wants to move its leg and it doesn't know how you left it? You can really confuse your dog."

The moral: Change the state of a contained object only through the containing object's interface.

"Aha!" you say. "If I employ the technique of encapsulation, then a method won't even know of the existence of any contained objects."

That's precisely the point. To walk your dog, you don't need to know of the existence of its legs. (And in fact, dogs with fewer than four legs can go for walks. There is even a case of a dog whose hindquarters rested on a little carriage; its "walk" method employed two legs and two wheels (these latter, one hopes, encapsulated within a "carriage" interface).)

Accessors Are Evil

Ok, this one's not funny. The title is deliberately over the top. But see why Allen Holub says Accessors Are Evil and see if he's talking about Demeter (among other things.) And take away the reminder that any time you write a getSomething method you should stop and ask yourself "is this trip necessary?"

BTW: I disagree with a couple of his assertions ... he's made a mess with UI code ... Swing is not an abstraction, it's a concrete implementation. I might buy a strategy pattern with an abstract factory to make renderers, but I guess he'd have to reference the whole GoF book. And in my world "log on" is a use case because without a use case I don't have requirements and without requirements I don't write code. Your mileage may vary.