views:

182

answers:

3

I'm familiar with standard listeners, esp. in Java. For example, if you have a collection of objects, it might support a set of listeners for different things: CreateListener, ChangeListener, DeleteListener. Each has one method (e.g. objectChange) that is passed a list of affected objects. An app using this collection could register interest in one or more of these by implementing and register listener(s). When things happen to the objects in the collection, the appropriate listener gets invoked.

But what if there are a number of these event types, perhaps similar but somewhat different. Would it make sense instead to define one listener class that has many methods. For example:

class EventListener
{
    void objectsCreatedA( Object[] newObjects );
    void objectsCreatedB( Object[] newObjects );
    void objectsCreatedC( Object[] newObjects );

    void objectsChangedA( Object[] newObjects );
    void objectsChangedB( Object[] newObjects );
    void objectsChangedC( Object[] newObjects );

    void objectsDeletedA( Object[] newObjects );
    void objectsDeletedB( Object[] newObjects );
    void objectsDeletedC( Object[] newObjects );
}

This seems to make it easier for an app that wants to register for many of these events - they implement many methods in one class, rather than defining many classes that each implements only one method. Any drawbacks or other suggestions?

Clarification edit: (sorry I got distracted with the holiday, not sure if this should be a separate post, but seems to make sense to follow-up on this one)

I should have specified that this code will be implemented in multiple languages, as a framework that client apps will make use of. For C++, implementing multiple interfaces is difficult.

A superset abstract listener could provide default do-nothing implementations for each method, so that a client extending it would only have to override the ones they care about. With this approach, we could later decide to add additional methods to the abstract class and existing clients would be ok (and can override those new methods if/when they choose to). And only one registration is needed with one invocation, rather than the alternative of many registration methods (with the app invoking one or many).

With this clarification, does a superset abstract class make more sense than individual ones?

+1  A: 

I would group that functions into an interface only if they are semantically similar (cohesion) and if it is very likely that an object interested in the event "objectsCreatedA" is also interested in "objectsCreatedB", otherwise you'll end with some classes with unimplemented functions: pretty ugly.

As an alternative, if the events are really so similar, you could pass a "type" parameter, so the receiver can factorize out some code and choose what event type to process.

akappa
On passing a type - but likely the object set being processed at one time is a mix of types (some Changed, some Created) - would you invoke the method multiple times, each with a different type, or would you have to pass a type with each object?
Cincinnati Joe
The logic would be the same as calling listener.objectsCreatedA(aBounchOfObjects);listener.objectsCreatedB(anotherBounchOfObjects); :listener.objectsCreated(Type.A, aBounchOfObjects);listener.objectsCreated(Type.B, anotherBounchOfObjects);
akappa
A: 

The only drawback I see to grouping all of those into one class is that the class could end up becoming fairly large and hard to read. That being said, if the listeners are not at all similar, you could end up with a massive class which a bunch of random functionality, which would have pretty high coupling.

If you do end up going this route, make sure that this listener only exists once (Singleton, static, whatever).

AlbertoPL
+1  A: 

Since classes can implement multiple interfaces, I don't see that this saves you anything other than declaring that a single class implements a series of different listeners. It may, on the other hand, force classes to implement methods they don't actually need to implement.

ColinD
That's a good point. Perhaps the methods could be grouped so that there are three interfaces. But depending on how the apps might want to make use of these listeners, might have to define 9 different interfaces, then let them choose to implement just the Change ones, or just the "A" ones, etc.
Cincinnati Joe