[Moved from LawOfDemeter
The argument here is that the LawOfDemeter maximizes the number of bridges that must be crossed. It is argued that the classes become coupled. Maybe this page should be called LawOfDemeterIsBridgePattern? or LawOfDemeterIsShieldPattern?.
(A quote from Graham Perkins on comp.object, through RonJeffries and JeffGrigg.)
- Q: "What are the consequences of violating the Law of Demeter?"
- A: "Joe Demeter sends his mates Largo Coupling and Minimo Cohering round to beat the shit out of your system."
minimizes logical coupling, but maximizes what could be called "physical coupling" -- the number of instantiated objects that need to be traversed for any particular operation. There are specific reasons why this might be bad. If performance is an issue, you might not want to incur the costs of implicitly navigating through a bunch of objects every time you call a top-level method. (This can be counteracted by caching intermediate objects, though that might be cumbersome in practice.) Similar issues can occur when you're using multithreading or distributed systems, where physical indirection can cause problems.
In practice, there's a trade-off between un-Demetered code and layers and layers of BridgePattern
. (Do you want your code to look more like a pomegranate, or an onion?) The layers can create maintenance cost, with structural changes rippling throughout your code.
The XP version of ShieldPattern is "Use the smallest possible shield." The LawOfDemeter is telling you to use Shield unnecessarily, because of a change which may or may not happen. YouArentGonnaNeedIt. When the dog needs to know about changes to its leg, that's the time to refactor and introduce the shield.
If you replace a.getB().getC().doSomething() with a.getB().doSomethingWithC(), all you do is increase the coupling and create an interface bloat in the B class. The B class will no longer be a conceptually consistent ADT.
The LoD should be about refactoring and rethinking your model. Change your classes, responsibilities, processes, interaction patterns. But don't just move the problem from one class to another.
What the above example does is to hide the origins of 'C' from the caller. Calling a.getB().getC() exposes the structure of both 'a' and 'B'. Without limitation to how far you can follow down this structure you are essentially including the types of 'B' and 'C' into the ADT of 'a' (and 'C' into 'B's ADT).
What you want to achive is a.doSomethingSensible(param, ...) and then from a caller point-of-view completely ignore what 'a' needs to do in order to achieve the desired effect. 'Sensible' may imply 'C' but what do you care? A caller of the object only requires that a certain effect be achieved - be that a returned object or a change in another object's state.
aims to help you reduce coupling by making such coupling really obvious. But it doesn't offer any automatic solutions. Perhaps it's even more usefully described as a CodeSmell
instead of a Law.
I would agree with this, except that the application of the LawOfDemeter may also be a code smell. Referencing an earlier comment, when you find that a dog needs to know about changes to its leg then this is also a code smell. Therefore, when the violation or application of a principle can both indicate a code smell, this is indicates a DesignPrincipleSmell.
For example, don't think the LoD is telling you to change this code
person deductionProfiles last stateTaxDeduction amount
to this code
It's not. It's forcing you to ask yourself: Why does this class really care that the state tax deduction amount is the last deduction profile of some random person?
Clearly this class is overextending itself. Refactor to give Person the responsibility to answer questions about current deductions. Or perhaps Person needs a Deduction
Summary object that supports getting the answers clients need. It's also possible that the thing the client wants isn't a Person after all, but just a Deduction
Stated another way, its possible you need to call
DeductionProfileSummary profileSummary = person.DeductionProfileSummary;
which could be shortened to:
In other words, its possible you need to violate the Law of Demeter.
Violations of the LawOfDemeter
are indications that your code needs refactoring. Heed them.
Additionally, uses of the LawOfDemeter are an indications that your code needs refactoring. Heed them as well.
[It seems to me that 'profileSummary.doSomething()' is already a violation of sorts (not of LawOfDemeter
, but of various other principles of object-oriented design). Profile summaries - forms in general - shouldn't do
anything... they might allow you to set fields, get fields, get calculated properties, and get a SceneGraph
that can be translated into HTML or a form. But the moment you start attaching methods to the 'profileSummary' to 'doSomething()', you start tightly coupling the class itself to the system. Better would be system.doSomethingUsefulWith(profileSummary). Similarly, a person (in a well factored system) shouldn't be responsible for knowing where his or her profile summary is. Consider, instead, database.getProfileSummary(person.getIdentity()). Now, supposing that only the 'system' knows where the 'database' is, the LawOfDemeter
would discourage: system.doSomethingUsefulWith(system.getDatabase().getProfileSummary(person.getIdentity())).]
I agree with some of the points you make in this case, but I was only playing off the example given above. The point really is that object A may have an inherent need to work with object C that is itself inherently associated with object B from an ontological perspective.