Re: acting in dependency upon the type of an object
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Sat, 17 Jun 2006 23:10:13 GMT
Responding to Ram...
A list (like a mixed element in XML) might contain texts and
other elements as entries. How to model theses entries? A first approach might be:
interface Entry1
{ int getType();
Text getText();
Element getElement(); }
(I am using a Java-like notation here.)
And here is how to process an element:
if( entry1.getType() == 1 )doSomethingWith( entry1.getText() ); if( entry1.getType() == 2 )doSomethingElseWith( entry1.getElement() );
There are actually two different problems here. The first is that basic stream-of-objects problem that a lot of OOPLs have a problem with. That is, you need a mechanism like getType so that the client can know how to deal with the list element. For example, the client has a particular collaboration in mind and just needs to know what interface to use on the element.
The second problem is that doSomethingWith and doSomethingElseWith imply that the nature of the collaboration is different. That is, the client collaborates differently with the list element depending on what it actually is. In OOA/D terms you really want to send a different message to the element depending on what flavor it is. In this case one really needs a different relationship with the element for each type:
1 accesses through
[List] --------------------+
| 1 |
| |
| R1 |
| |
| contains |
| * |
[Entry] |
A |
| | R4
+------+--------+ |
| | |
[TextEntry] [ElementEntry] |
| 0..1 | 0..1 |
| | |
| R2 | R3 |
| | |
+-----+ +------+ |
| | |
used by | | used by |
1 | | 1 |
[Client] ------------------+
1
Now one uses getType to instantiate and navigate the proper R2 or R3 relationship. One way to do that is via:
Entry myEntry;
myEntry = myList.getEntry(); // navigate R4
switch (myEntry.getType()) // dispatch on entry flavor
{
case 1:
{
TextEntry myTextEntry;
// instantiate R2
myTextEntry = (TextEntry) myEntry);
doSomethingWith (myTextEntry); // navigate R2
break;
}
case 2:
{
ElementEntry myElementEntry;
// instantiate R3
myElementEntry = (ElementEntry) myEntry;
doSomethingElseWith (myElementEntry); // navigate R3
break;
}
}
We still have a switch statement but it is pretty benign because all it is really doing is instantiating a relationship based on the Entry flavor. We are doing different processing on each flavor of Entry, but that is already intrinsic in the problem and has been formalized by subclassing Entry. IOW, we have used subclassing specialization to capture an important aspect of the problem and the diffrent processing is associated with the relationship being navigated rather than the ntry type.
Note that you can take this decoupling further. You could subclass Client to reflect the different processing contexts of ...With and ....ElseWith and then use the GoF Visitor pattern. (The subclasses of Client would correspond to ConcreteVisitors while the subclasses of Entry would correspond to ConcreteElements.) That would eliminate the switch statement and the casts. However, that is pretty elaborate and most situations don't justify it, especially if the number of options is small.
A compromise would be to provide an overloaded doSomething method in the example above that corresponds to ConcreteVisitors. This decouples the difference in processing from the entry type more clearly. Note that this would be rather similar to your alternative implementations.
One point I am trying to make here is that there is nothing inherently wrong with a switch on getType. Because most OOPLs do not provide a dispatch mechanism for streams of arbitrary objects, you need to provide the infrastructure via getType, Visitor, or some other mechanism. The trick is to tie the dispatch on getType to relationship instantiation rather than how Client collaborates. A second point is that you can tie the arbitrary dispatch mechanism to explicit subclassing and relationships in the OOA/D to better capture the problem. That, in turn, enables other decoupling mechanisms like Visitor or overloaded methods to manage the actual collaboration.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- Prev by Date: Model Metrics
- Next by Date: Re: OO versus RDB
- Previous by thread: Model Metrics
- Next by thread: editors and metamodels
- Index(es):
Relevant Pages
|