Re: dynamic_cast is ugly!
In message <nRyBj.5561$Y33.3445@trndny07>, H. S. Lahman
<hsl@pathfindermda.com> writes
Responding to Nieminen...
(1) Use separate homogeneous collections rather than heterogeneous
collections. Then the client who needs specific types of objects can
navigate the appropriate relationship to the right collection.
In my particular case I am (usually) keeping objects of a certain
type
in a container of that type, and I access this container directly when
it's possible to do so (eg. to perform an action on some or all the
objects of that type, as long as this action is independent of any other
objects in the system).
The problem is that not all actions I need to perform can be
applied
to objects independently of other objects. In particular, sometimes some
actions need to be performed in a certain order. The two problems are
that the objects in the object-specific container might not be in this
order already, and secondly, even if they were, some actions have to be
performed to all existing objects (regardless of their type) in a strict
order, and cannot be performed on a per-type basis.
This is actually an easy problem to solve with multiple homogeneous
collections without any dynamic_cast.
Ordering is a natural responsibility of collections and the natural
approach is for a getNext collection interface to provide elements in
the correct order from its implementation. So the ordering is not
======================
directly a concern of clients processing the collection elements.
================================================================
Consequently the ordering is only related to the element type through
problem space serendipity. Hold that thought for a moment...
If I understand the problem correctly you have:
[ClassA]
|*
| accesses
|
| R1 <<ordered>>
|
| 1
[Client]
+ actionForA()
+ actionForB()
+ actionForAll()
| 1
|
| R2 <<ordered>>
|
| accesses
| *
[ClassB]
where the relevant collections implement the R1 and R2 associations.
The ordering of the R1 collection is suitable for actionForA() that
needs to process members of [ClassA]. Similarly, the ordering of the R1
collection is suitable for actionForB() that needs to process members
of [ClassB].
So the tricky part is dealing with the ordering for actionForAll(). The
simplest case is that ordering of R1 and R2 is the same and that
actionForAll() just needs to interleave the results of getNext from the
two collections. I'll deal with such interleaving in the discussion of
(2) below.
[snip trickier problem, not relevant to my point]
Note that it is quite fair for the client to utilize a particular
interface for ordering because ordering is a *collection*
==========================
responsibility and a characteristic of the relationship that has
==============
nothing directly to do with what classes the collection objects belong
to.
[...]
This becomes relevant for the interleaving. There has to be some
attribute that is a context variable for the ordering or else the
collection sets could not be ordered in the first place. For the sake
of example, let's assume all the objects have a 'size' attribute and
actionForA() and actionForB() require ordering in ascending order of
size, while actionForAll() requires descending order of size.
It is quite fair
!
for actionForAll() to obtain the next element from each collection and
compare sizes to determine which one of the two to process next.
actionForAll() then does getNext() on the appropriate collection to
replace the element just processed, and continues the interleaving in
this manner.
This processing does not directly depend on the object types. It just
depends on the 'size' attribute and the fact that the R1 and R2
collections provide the correct order for individual elements when
taken one-at-a-time. So 'size' is a context variable that is
synchronized with the R1 and R2 collection ordering to make
interleaving simple for actionForAll().
So now you have to expose that attribute, and the client has to have
access to the ordering relation which was previously encapsulated in the
collection.
And if the number of collections increases beyond two, that "simple
interleaving" doesn't scale well, as it starts to look more and more
like a complete (partial) sort, so really the client, not the
collection, is now responsible for the ordering.
An interesting tradeoff.
--
Richard Herring