Re: Internal State vs. Navigating Associations
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Thu, 21 Sep 2006 21:08:14 GMT
Responding to McGill...
As a newcomer to OO design, I've been wrestling lately trying to wrap
my mind around the "Tell, Don't Ask" principle and the law of Demeter
for methods. I have been trying to avoid query/decision operations of
this nature:
Bar bar = foo.getFrozzledBar();
if (bar.isFranted()) // do something else
under the assumption (here I am trying to apply "Tell, Don't Ask") that
in this example foo's internal state (bar) is being exposed. Instead I
try to replace the above with a single, more meaningful method on foo,
containing the conditional in some form.
The first thing to note is that "tell, don't ask" is orthogonal to LoD. "Tell, don't ask" is about how one defines the responsibilities of an object while LoD is about what one object knows about another.
The question this has prompted me to ask: in what situations is bar a
part of foo's internal state, and in what situations is it really just
an object to which foo has an association? If bar *is* just an
associated object, is it then OK to navigate the association in the
above fashion?
As you recognize, the crucial question related to "Tell, don't ask" is: what object knowledge properties should be exposed publicly? I submit that "Tell, don't ask" is actually irrelevant because the OO paradigm already provides methodological construction techniques, particularly problem space abstraction, that already minimize what is exposed.
All objects are abstractions of entities from some problem space. When we abstract those entities we abstract intrinsic responsibilities for things the entity needs to know or needs to do _in order to solve the problem in hand_. So, by definition, any characteristic we need to solve the problem in hand must be abstracted as a responsibility. The corollary is that we only abstract characteristics that we need to solve the problem. Therefore we should end up with no more and no less responsibilities than those we need to solve the problem in hand.
There is an issue around public vs. private responsibilities. Certain responsibilities, such as the current last address in a ring buffer, are clearly only relevant to the implementation of an object. Other responsibilities, such as the current color of a traffic light, are clearly responsibilities that relate to collaborations in the overall solution for traffic control software. So the criteria for public vs. private is pretty straight forward. If, in order to solve the problem in hand, some other object needs the information the object in hand is responsible for knowing, that knowledge responsibility is a public responsibility.
There is also an issue around capturing business rules and policies statically in state variables and relationships or capturing them dynamically in behaviors and state machine transitions. However, that is a fundamental design choice. Once the choice is made to use state variables, then those that are necessary to solve the problem in hand become clear.
Having said all that, the example you cite is really another special situation: embedded objects. Since 'bar' is an object with its own responsibilities, the real question is: Is 'bar' a peer of 'foo' or part of its implementation?
If 'bar' is a peer of foo, then all one is really doing is navigating a relationship path, R1 -> R2:
R1 R2
[Client] -------------- [Foo] ----------------- [FrozzledBar]
That is quite normal for an OO application and has nothing to do with either "tell, don't ask" or LoD. That's because relationship implementation, instantiation, and navigation is orthogonal to class semantics. (For example, full code generators for OOA models routinely employ generic aspects to implement relationships that are completely independent of classes.)
Where it would be a problem is if [FrozzledBar] was embedded in [Foo] as part of its implementation. The OO paradigm says that such implementations should be hidden. There are exceptions, though. Common computing space data holders (String, Array, ComplexNumber, etc.) are essentially fundamental data types so they are treated like ADT scalar knowledge attributes. IOW, one evaluates whether they need to be exposed publicly as if they were were ordinary knowledge responsibilities; if they are needed by other objects to solve the problem in hand, they should be exposed.
OTOH, any object that abstracts an entity in a non-computing problem space should almost always be a standalone peer object (i.e., not embedded in another object's implementation). That's because it /is/ an identifiable entity in the problem space just like any other problem space entity that one abstracts.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- References:
- Internal State vs. Navigating Associations
- From: Matt McGill
- Internal State vs. Navigating Associations
- Prev by Date: Re: what's the future of Object Oriented Programming
- Next by Date: Re: what's the future of Object Oriented Programming
- Previous by thread: Re: Internal State vs. Navigating Associations
- Index(es):
Relevant Pages
|