[stephen] > My goals for [collections] is to add something small and
simple that doesn't prevent a user adding something more complex.
[michael] > I think I would prefer multiple listener interfaces and a
simple event to a single listener interface and either a hierarchy of
event classes or a typed-using-masks event.
Obviously one of the concerns for the notifying package is that it be
small and easy to use, yet we also want it be flexible and powerful
(when required). This is why NotifyingCollections uses a pluggable
event system. And the simplest usage for NotifyingCollections is indeed
small and simple. The user need only know about one decorator (e.g.
NotifyingList), one listener (CollectionListener), and one event
(ModifyingEvent). The default 'simple' event package in
NotifyingCollections is just that, simple. The package can be used as
easily as this:
NotifyingCollection nc =
NotifyingCollectionsUtils.notifyingCollection( c );
nc.addCollectionListener( myCollectionListener );
// do something
nc.add( "hello world" )!
ModifyingEvent event = myCollectionListener.getEvent();
assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
The 'simple' package has one event class, SimpleCollectionEvent. The
user does not even need to know of this class as it is simply a minimal
implementation of ModifyingEvent (which is abstract). The only data
provided is the size of the collection before and after the event. It
does not contain references to the arguments that caused the event to
be fired or references to the items added/removed etc. from the
collection by the event. That would be considered rich data.
The 'rich' event package has an event hierarchy, which (I hope)
captures the semantics of collection manipulation quite well. There is
an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
9 events. I believe this is close to the minimum number of classes
necessary to richly model collection manipulation in a clean OO manner.
(Though if anyone can do better, they can just plug in their own event
package!).
The third event package, 'monolithic', is an attempt to capture rich
data (like the 'rich' package) in a single event class, i.e. the design
idea that has been floated on the list. While a single event class
works fine for SimpleCollectionEvent, it does not work well with rich
data.
Let's take three collection manipulations, for which we want to gather
rich data:
a) remove several items from a list (e.g. #removeAll)
b) set a list element
c) put an entry into a map
What data do we need to capture?
a) The removed items, and the indices of each removed item (note that
they are not necessarily in sequence)
b) The value of the list element, the index, and the previous value at
that index
c) The key, the value associated with that key, and the previous value
associated with the key (if any)
So, in this *one* monolithic rich event class, we need a method:
1) to access added/removed/set items (e.g. #getItems: Collection)
2) to get indices (e.g. #getIndices: int[])
3) to test if there was a former value associated with an index/key
(e.g. #hasPreviousValue: boolean)
4) to get previous value if any (e.g. #getPreviousValue: Object)
5) to get key associated with a Map put event (e.g. #getKey: Object -
though this could be possibly be shared with #getIndices)
Those who already see what's wrong with this can skip this section ;)
For the unconvinced, let's say we add an item to a plain ol'
collection:
nc.add( "hello" );
MonolithicEvent event = myListener.getEvent(); // grab the event
// from a listener somewhere
This monolithic event will have a method #getIndices, which has no
meaning in the context of a collection. Presumably #getIndices should
return null in this case? (as a zero-length indices array would violate
the invariant that the number of indices should be the same as the
number of added/removed items). Not pretty. There are a whole bunch of
similar methods in MonolithicEvent that are specific to the specialized
types in collections, and don't belong in a general type. This is a
textbook example of when to use subclassing.
I don't argue that the included 'rich' event package is the only or the
best possible model of collections manipulation. Indeed I completely
redesigned the package at least once. What I do argue is that this
shows a) the need for a flexible event system and b) the difficulties
with trying to capture rich heterogeneous data in a single class.
- Neil
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]