Re: Exposing contained types.. Especially LISTS
- From: Veloz <michaelveloz@xxxxxxxxx>
- Date: Wed, 26 Dec 2007 08:04:16 -0800 (PST)
Just to be clear, if other objects than A need to collaborate with B,
then B should be a peer object and A should contain only a reference to
it (or some other implementation of the relationship to a peer B). B's
responsibilities should not be available through A's interface (i.e., by
A acting as a middleman in collaborations).
Other objects do need to collaborate with B.. B is actually a list of
objects in this case. Imagine that A is a "book" class and B is a
list of chapter objects. Both the book and the chapters are objects
in their own right. Code may want to interact with A's methods (add
chapters, etc) and may also want to interact with the chapter objects
(add a sentence, for example)
Now, the List holding the chapters is of course a legitimate object
too. So we really have three kinds of objects. The Book object (what
we've been calling A), the List object (what we have been calling B)
and the actual chapter objects.
The list of chapter objects is very strongly related to A (the Book).
A "has" a "list" of "chapters".
In the actual software, A will have a field of List type, to which
outsiders should be able to add chapter objects and/or interact with
existing chapter objects.
The question was whether or not I should expose the List type fully
and publically (i.e., let code interact with the list object
directly), or whether I should view the list as a private detail of
how I am storing the chapters, and instead expose some methods in A
that let outside code work with the list semantically. That is,
instead of outside code calling A.TheList.Add(chapter), which shows
exposing TheList directly, the user would call A.AddChapter(chapter)
and privately A, would call TheList.Add(chapter).
It also seems to me that A should be the primary "holder" of TheList
of its chapters. That is, if some software wants to interact with a
certain chapter belonging to a certain book, it should expect to have
to interact with that book object (i.e., to get access to the list of
chapters).
So from this perspective, A and TheList are peers in that they are
both public objects in the system. They are parent/child in that A is
the original and permanent" "holder" to the reference to TheList ,
Other code may make reference to TheList (or to objects in TheList)
but in any event, A can always be relied on to be the "authority",
having the reference to TheList of its chapters.
Perhaps the way I am using parent, owner, and sibling is confusing
this topic?
Concretely, if a Test Product contains a List (of Feature Groups) then
we are saying client of Test Product should be able to interact with
the List without having A be the middleman, right?
Yes.
This makes perfect sense to me... but there are other posts out there
saying that A should "hide" B (as an implementation detail) and
surface its own interface, which might in some cases delegate to B,
privately. I think that's what was confusing me...
The problem lies in the OOPLs. They are 3GLs and they must necessarily
make compromises with the hardware computational models. Thus all the
OOPLs are inherently procedural and employ procedural message passing,
procedural scope, and procedural block structuring because that is what
3GL abstraction of the computer is about. (Though some OOPLs, like
Smalltalk, do a good job of hiding it.) So the 3GL type systems marry
message and method via a procedure signature.
As I mentioned, that leads to substantial problems with physical
coupling than can make the code difficult to maintain. A large portion
of dependency management refactoring guidelines are aimed at mitigating
that physical coupling. (Dependency management is largely irrelevant in
UML OOA/D models because they use class systems rather than type systems
and separate message and method.)
The notion of "hiding" B is rooted in a desire to mitigate physical
coupling by using encapsulation. That is fine up to a point. A lot of
refactoring technique involve creating abstract classes and "buffer"
objects (e.g., the Facade pattern) to hide the details from clients. But
those classes are just providing generic access and they are dedicated
to that generic access.
However, when A exposes B's properties in its interface, one really
isn't hiding B; instead one is just duplicating B in A's interface. IOW,
A already has a unique suite of responsibilities in the problem solution
before one worries about dependency management refactoring. In effect,
one is adding B's properties to those that A already has. That is what
is creating the problem because one is trashing A's cohesion.
That is quite different than providing a facade or delegation to hide
/details/. Consider a typical POS web site where the user navigates a
hierarchy of pages. One can describe that hierarchy with a single class:
0..1 child of
[Page] ----------------+
| 0..* |
| parent of | R1
| |
+-------------------+
The R1 relationship captures everything one needs to know about the
hierarchy. Now one can navigate up and down the tree easily using
accessors in [Page]. But that gets tricky when one needs to keep track
of where one has been (e.g., for a depth-first traversal). So a common
solution is:
[Tree]
| 0..1
| root of
|
| R2
|
| 1 0..1 child of
[Page] ----------------+
| 0..* |
| parent of | R1
| |
+-------------------+
Now all the [Page] does is hold page data and referential attributes to
instantiate R1. The traversal algorithm is encapsulated in [Tree] and it
keeps track of where it has been.
This is a case where the clients now all talk to [Tree] to navigate the
tree (e.g., via getNext, get(linkID), or whatever). Inserting the [Tree]
class to encapsulate the traversal algorithm makes the solution more
robust. It also very effectively hides the details of the tree
organization from clients (e.g., the tree might actually be implemented
as a B-Tree or Red-Black tree). To that extent "hiding" [Page] is a Good
Thing.
But you will note that [Tree] is a new class expressly created to do the
hiding and it has no other responsibilities than traversing the
structure, which is inherent in the implementation of the tree. IOW,
[Tree] is a delegation of responsibilities of [Page] in the first
diagram. The result is a new [Tree] class and a simplified [Page] class.
Also critical to dependency management, [Tree] provides a more generic
interface for clients so that they do not have to know how the tree is
actually implemented. Thus one creates [Tree] to hide details of [Page]
from clients.
OTOH, note that the clients still talk directly to [Page] to do page
collaborations (e.g., getItemName or getPrice). They just get the Page
reference from Tree. IOW, [Tree] is a smart list collection. But they
don't talk to [Tree] about [Page] responsibilities. They only talk to
[Tree] about tree navigation responsibilities, which are no longer
embedded in [Page] accessors.
If I was going to provide a pithy summary of this distinction it would
be: don't hide detail by adding responsibilities to other objects that
already have disparate responsibilities in the solution. Which is just
another way of saying the Separation of Concerns Rules.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
h...@xxxxxxxxxxxxxxxxx
Pathfinder Solutionshttp://www.pathfindermda.com
blog:http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
i...@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring:http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- Follow-Ups:
- Re: Exposing contained types.. Especially LISTS
- From: Daniel T.
- Re: Exposing contained types.. Especially LISTS
- References:
- Exposing contained types.. Especially LISTS
- From: Veloz
- Re: Exposing contained types.. Especially LISTS
- From: H. S. Lahman
- Re: Exposing contained types.. Especially LISTS
- From: Veloz
- Re: Exposing contained types.. Especially LISTS
- From: H. S. Lahman
- Exposing contained types.. Especially LISTS
- Prev by Date: Re: Exposing contained types.. Especially LISTS
- Next by Date: Re: Exposing contained types.. Especially LISTS
- Previous by thread: Re: Exposing contained types.. Especially LISTS
- Next by thread: Re: Exposing contained types.. Especially LISTS
- Index(es):
Relevant Pages
|