In essential skills for the agile developer, in the needs vs capabilities interface, chap, 12, I'm trying to understand the main solution proposed to the challenge of applying the LAW OF DEMETER that the author mention by the end of this chapter.
To make the story short.
We start with the following study case:
public class City {
public string name{};
public City twinCity{};
public Street[] streets{};
}
public class Street {
public string name{};
public House[] houses{};
}
public class House {
public int number{};
public Color color{};
}
Where the author state that:
Models like this encourage us to expose rather than to encapsulate. If your code has a reference to a particular City instance, say one that maps Seattle, and you wanted the color of the house at 1374 Main Street, then you might do something like the following:
public Foo() {
Color c = Seattle.streets()["Main"].
houses()[1374].
color();
}
The problem, if this is done as a general practice, is that the system develops dependencies everywhere, and a change to any part of this model can have effects up and down the chain of these dependencies. That’s where the Law of Demeter, which states2 “Don’t talk to strangers,” comes in. This is formalized in object systems as the Law of Demeter for Functions/Methods. A method M of an object O may only invoke the methods of the following kinds of objects:
- O’s
- M’s parameters
- Any objects instantiated within M
- O’s direct component objects
- Any global variables accessible by O
and suggest that when applying the LAW of DEMTER we should aim for something like
public Foo() {
Color c = Seattle.ColorOfHouseInStreet("Main",1374);
}
and quickly warns from the following:
Although this would seem to be a wise policy initially, it can quickly get out of hand as the interface of any given entity can be expected to provide literally anything it relates to. These interfaces tend to bloat over time, and in fact there would seem to be almost no end to the number of public methods a given glass may eventually support.
Then after a quick detour at explaining the the problem of coupling and dependency, where he mentions the importance of separating a client and its service by the interface of the service, and possibly furthermore by separating the client "needs interface" from the "service capability interface" via the use of an adapter as something ideal but not necessarily practical;
he suggests that to remedy to the problem, we could combine the LAW of DEMETER and the needs/capability separation, using a facade pattern as explain below:
From the original dependency
In applying the law of demeter and the needs/capability interface separation we should initially get:
But given that it is just impractical especially from the point of view of mocking, we could have something simpler with a facade as follow:
The problem is that i just don't see how that exactly solve the problem of not violating the Law of Demeter. I think it maintains the law between the original client and the original service. But it just moved the violation within the FACADE.
I'd say, from your descriptions, he has merely introduced a black-box component around the Cirty/Street/House functionality in the form of the CityMapFacade. Further, that component adheres to a public facing interface in the form of an interface, IClientNeeds. This kind of black-box encapsulation protects, and makes testable, the larger application because the complexities of the City/Street/House relationship are not exposed. It seems what was once old is new again :) This kind of black-box component-style methodology (for lack of a better term) has been around for a long time. It focuses on creating reusable, encapsulated components of functionality with a well defined interface. The client doesn't care about the implementation as long as the public-facing contract is fulfilled. The component is replaceable, upgradeable, mockable. Within the component, the complexity is also diminished because it is only responsible for an isolated subset of the application. It would typically be fully unit testable to ensure it correctly implements its public contract / interface. In my opinion, the author has brushed a deeper discussion of this all under the rug so as to simplify his explanation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With