Re: Law of Demeter can be supported without eliminating object coupling
- From: "Daniel T." <daniel_t@xxxxxxxxxxxxx>
- Date: Tue, 19 Jun 2007 22:12:45 GMT
In article <yqWdi.7444$gI4.6610@trndny06>,
"H. S. Lahman" <h.lahman@xxxxxxxxxxx> wrote:
Responding to Daniel T....
OK, per you offline request, I will take one more shot at this. I think
there are several disconnects here that I would summarize as follows...
Thanks. :-)
After reading your summary carefully, I think it is safe to say that we
have completely different interpretations of the LoD, all I can say in
my defense of the discussion/debate is that I am using *the* primary
source to support my position, not Wikipedia or other tertiary sources.
Regardless, we could argue until the cows come home about what
Lieberherr and Holland *really* meant when they wrote what they wrote.
Consider the example you quoted to Guild:[snipped other points which are covered below]
C++:
void C::M(A* p)
{ ...; p->F1()->F2(); ... }
where p is an instance of class A and F1 returns a subpart of p. If
the immediate composition of A changes the method M may have to
change also because of F1. (page 13)
Third, whether the example violates LoD depends on what F1() is. If F1
is a method, then I agree the example violates LoD and good OO practice.
But if F1 is simply an accessor for a referential attribute, there is
nothing wrong at all.
You make a strong distinction between "getters" (or knowledge accessors)
and setters (you have called them [proper] methods.) You don't even
consider getters to be behaviors at all. I think they are, even outside
the 3GL level, providing knowledge is a behavior in my book, being
responsible to provide that knowledge is a behavior responsibility.
A more interesting question is: if 'p' is passed to the caller's method,
is it a friend of the caller even though the caller just passes it
through to C? There is a rather nasty conundrum there. Corollary
question: how is that chain of calls different than C.M navigating
through exactly the same relationships as those in the call chain to get
to 'p'?
Here we get at the heart of our different points of view, if neither of
us ever mention LoD again, this is the crux. You say that
B.getC().getD().do() is better than B.do() where B::do() { c.do(); } and
C::do() { d.do(); }. I say that they are both wrong, they both suffer
from the same basic flaw, a fundamental disconnect between the thing
that is doing and the thing that needs to know about the doing.
Consider these two implementations:
class C
{
private:
A* myA;
public:
void M () {
// do something to change solution state
myD* = myA->myD; // navigation
if (myD->color == FUCIA) // navigation
myD->F2(); // collaboration
}
}
class A
{
public:
D* myD;
...
}
class D
{
private:
int myAttr;
public:
void F2() {myAttr++;}
}
****VERSUS****
class C
{
private:
A* myA;
public:
void M () {
// do something to change solution state
myA->F1();
}
class A
{
private:
D* myD;
public:
F1() {
if (myD[i]->color == FUCIA) //navigation
myD->F2(); // collaboration
}
}
class D
{
private:
int myAttr;
public:
void F2() {myAttr++;}
}
Both implementations result in D.myAttr being incremented for a
particular D after C.M changes the solution state and the selection of
that D is exactly the same in both implementations. Now assume that
requirements change and we only want to increment myAttr if its color is
PUCE.
In the first example C.M must change, which is quite reasonable because
the criteria for selecting a particular friend from the restricted set
of D friends is clearly a personal matter between C and D in this
particular collaboration. LoD and peer-to-peer collaboration have
ensured the change is made where the collaboration semantics are defined.
But in the second example A and only A must change. From a
maintainability viewpoint that is clearly wrong because A has nothing to
do with the collaboration between C and D.
The biggest problem with the first example above (the one you champion)
is that C is performing some action and then deciding, on its own with
no help from anyone, that a particular D object is interested in the
fact that the action was performed but only if that D object reports
that its color is FUCIA. That in and of itself raises huge red flags for
me. Who is C to make such bold assumptions? It seems to me you are
breaking your own rules about the proper use of notifiers.
I have already shown a Rectangle example in another post today. Clearly
messing around in another objects guts is inappropriate, I expect we
both agree with that, or there is a disconnect here as well. So I expect
that you don't consider the D object as part of the A object's guts in
the example you cited. Would the situation be different to you if a
composition relationship were being used? If for example, the UML
clearly showed that the D object was a *part* of the A object and A's
state was, in part, dependent on D's state.
In the mean time, your example also clearly breaks the "tell, don't
ask" principle. "do not ask [objects] questions about their state, make
a decision, and then tell them what to do."
<http://www.pragmaticprogrammer.com/ppllc/papers/1998_05.html> Taking
that into account, more of the behavior clearly belongs in D. But even
that is unacceptable if A isn't really interested in what C does.
Given the context provided, the proper solution is probably more like:
class C {
private D itsD;
public void M() {
// do something to change solution state
itsD->F2();
}
}
class D
{
private:
int myAttr;
public:
void F2() {
if ( color == FUCIA )
myAttr++;
}
}
Class A would be in charge of setting up the linkage between C and D...
.
- Follow-Ups:
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- References:
- Law of Demeter can be supported without eliminating object coupling
- From: tomjbr . 41840400
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Re: Law of Demeter can be supported without eliminating object coupling
- From: Daniel T.
- Re: Law of Demeter can be supported without eliminating object coupling
- From: H. S. Lahman
- Law of Demeter can be supported without eliminating object coupling
- Prev by Date: Re: Law of Demeter can be supported without eliminating object coupling
- Next by Date: GUI enabling/disabling design pattern
- Previous by thread: Re: Law of Demeter can be supported without eliminating object coupling
- Next by thread: Re: Law of Demeter can be supported without eliminating object coupling
- Index(es):
Relevant Pages
|