views:

263

answers:

5

I'm trying to find an elegant OOP solution for the following problem.

Assume we have a collection of POJOS, events in this case, where each POJO is possibly different class. We need to process this collection, using different rules for each POJO class (or type).

A basic assumption is that we can't decorate the POJOs with appropriate handlers, since we don't control their generation, and receive the collection as is. Thus, any mechanism for this falls into the same trap. However, item 3 stil deals with this possibility.

There are some possible solutions, some very ugly, some more elegant but complicated:

  1. The obvious solution, and the ugliest, is using instanceOf operators to pass POJO to handler.
  2. A slightly better modification of 1, is to use a chain of responsibility for this, with chained dispatcher, so that new types just need a new dispatcher. However, each dispatcher stills needs instanceOf.
  3. Create enhanced objects, not POJOS, where each object holds a reference to its handler. This creates a coupling between POJO and our processor.
  4. Create (I know how to do this correctly in Java) a dispatcher service which registers handlers to the specific event class, and use generics (Typesafe container, as in effective java) to dispatch event to handler.

4 is the most elegant, but I was wondering if there are any better ideas.

A: 

I have used the solution in number 4 in this scenario and I think its a good one. I will also look for other opinion on better solution.

Bhushan
A: 

4 is the best of the solutions you present. #1 & 2 will be painful with a mess of instanceof's floating around.

Another solution: annotate each class with it's dispatcher method. You won't need a central place to handle the dispatcher calls and the POJO/dispatcher won't be coupled outside of the annotation.

Mike Reedell
He might not be able to annotate them as he is not responsible for their creating and this might also mean that it is a 3rd party class.
willcodejavaforfood
+3  A: 

Simplification of #4:

Use a Map to store the handler for each event class.

Map<Class, Handler> classHandlers = new HashMap<Class, Handler>();
classHandlers.put(EventA.class, new EventAHandler());
classHandlers.put(EventB.class, new EventBHandler());

Now use the class of the event to get the handler for the event.

Handler handler = classHandlers.get(event.getClass());
handler.handle(event);

Of course this requires knowledge of all possible event classes at coding time and is thus less flexible than an external event dispatcher.

Bombe
You will allways know all existing event classes at coding time :-) Each time you are adding a new class, you need to add a new handler, and then you are coding...
KarlP
+1. "This requires knowledge of all possible event classes at coding time" : seems to be part of the basic requirements, for me.
Olivier
Even if you don't know them all, you create a default handler that simply logs the unhandled POJO class somewhere. Now you know what you're missing.
Ian McLaird
This gets really messy if you have lot of subclasses or different implementations of interfaces.
pjesi
Of course, for every subclass you need one put() method call, but “messy” is something else entirely. :)
Bombe
This is similar to the command pattern. The mapping of class to handler could be put into configuration to enable to mapping to be easily maintained. Adding new handlers would just require adding a new jar for the handler to the classpath.
pjp
+1  A: 

Assume we have a collection of POJOS, events in this case, where each POJO is possibly different class. We need to process this collection, using different rules for each POJO class (or type).

Congratulations If the classes of POJOs are stable (new class types aren't often added) you've just described the motivation for using the Visitor Pattern!

Even better, because you probably want to do different things to your collection of POJOs, you can create an AbstractBaseVisitor and extend it to handle the different things you need to do!

This will require putting a tiny wrapper around each POJO, with one wrapper class per POJO class, to add a visit() function that calls back to the Visitor.

tpdi
Unless I'm missing something, this doesn't solve the problem. You need a mechanism to assign the correct wrappers, this is the same problem.
A: 

The question is actually not language agnostic at all. In some languages you could easily decorate the classes. But let's stick to Java. Even there I say "it depends".

An apparent thing we would like to do is some sort of auto-discovery of the handlers. For example, annotate your handlers with a @Handler(handles=PojoA.class) annotation, then scan for all classes annotated with @Handler (either the messy way that basically requires the class files to be loaded or using something like Scannotation).

If you are running in a context such as Spring, an even more interesting option arises. You can get all beans implementing a certain interface, such as the following:

public interface Handler<T> {
    void handle(T object);
}

and then find them in your dispatcher code:

Collection<Handler> handlers = applicationContext.getBeansofType(Handler.class).values();
for (Handler handler : handlers) {
    Method handleMethod = handler.getClass().getMethod("handle", Object.class);
    Class<?> type = handleMethod.getParameterTypes()[0];
    register(type, handler);
}

(admittedly, the code above is untested)

I realize I go out of the boundaries here. My point is that the elegance of the solution depends on your language of choice, what external tools you are willing to use and what framework you are using.

waxwing