Re: acting in dependency upon the type of an object



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



.



Relevant Pages

  • Re: LSP and subtype
    ... As long as all foo overrides respect the invariants, pre- & postconditions that Base documents/relies on then *any* imaginable client code will run just fine with *any* subclass object of Base, won't it? ... The relationship between the Client and the member of the tree needs ... capture the constraint on the collaboration that the Base.foo ... assignTarget that is different enough to warrant subclassing. ...
    (comp.object)
  • Re: Survey Design
    ... It is an Incredibly Bad Idea to design your database based on a form. ... what's the use of ease of entry if you can't get the data back out to report ... If you absolutely MUST have a data entry form that looks like the survey, ... The final result would be something like: Client X has taken the ...
    (microsoft.public.access.tablesdbdesign)
  • Subform Dataentry Problem
    ... with its subform having a new entry already created and data from the ... Main form frmBilling: Contains client information when it opens, ...
    (microsoft.public.access.forms)
  • Re: DNS A Record Order.
    ... We will have to look at a host file entry. ... IF your client doesn't change subnets. ... based on the subnet of the querying client. ... Instead of the website you're using, I suggest to use OEx (Outlook Express ...
    (microsoft.public.win2000.dns)
  • Re: Objective criticism of inheritance
    ... Many of the concepts are good from my experience programming, but the one thing I can't figure out is inheritance. ... Subclassing is just about defining set membership. ... The reason a tree form is used is because an OO class also defines a /set/ of properties that all its members have. ... If the client accesses the responsibility through a superclass interface, then that means the client does not care which implementation is used. ...
    (comp.object)