views:

374

answers:

5

I have a class that should read a message, extract its type from the envelope and then call a method that have to process the message; at each message type is associated an enum member.

There are 30+ message types.

One way to dispatch the message is to just use a switch, but it's really ugly and error-prone (have I already tract that case? have I tract that case two times?).

One another way is to define an interface with a single method process(data) and create one class for each message type that implements that interface, register those classes with a map and, in the code that should process the message, just call map.get(messageType).process(data); but it's really annoying to create 30+ classs.

One another way is to use reflection: define one function for each messagetype, with a precise signature and pattern name, like processMessagetype; then create a map from messagetype to Method (filled with a simple search upon getDeckaredMethods()) and then do something like: map.get(messageType).invoke(this,data).

What method you should use? What's the overhead of using java's reflection?

A: 

You don't say what your process() method is going to be doing, but I would be surprised if any overhead in dispatching a method call is going to be at all significant.

I would make the language and OO system work for you, and create an interface/abstract base class with the appropriate method implementation(s).

Remember that premature optimisation is the root of all evil (Knuth)

Brian Agnew
A: 

I would think that the first method/algorithm you described (a Map of message type to class) would be easier to manage over time with updates, maintenance, etc.

The second pattern you describe would basically involve having a class with about 30+ methods in it, correct? That would be quite a pain to manage over time.

Does each message type require truly unique processing logic? By creating implementations of an interface to process the message, you could probably benefit from a type hierarchy, i.e. a superclass that can handle parsing a certain family of messages, and then you just have to override it in areas where messages of that family differ...

matt b
Good point about the code reusability issue of the various methods.Yes, the logic is different for each function, which are really small (typically they just notify some classes of the event associated with the message and nothing more).The small factor of the various functions (2-3 lines of code) makes me think about reflection; otherwise I'll surely go with the Interface solution.
akappa
+1  A: 

You could add the process method to the enum.

What exactly is wrong with a big switch (with each case just calling a method)?

The major cost of reflection is that it tends to make code suck. ;)

Tom Hawtin - tackline
+1 for pointing out to the real cost of reflection
dfa
+1  A: 

Reflection has a big overhead if you're looking for good performance. If your routine (message dispatch) is going to be used over and over the polymorphism alternative is better. Also, IMO it's better if looking in a OO perspective, since as stated by Brian on his answer, it's easier and cheaper for maintenance.

Your clas handling 30+ messages can easily grow to 100+ messages, then you will have a class with 100+ methods, add the private methods too and code reuse will be hard and your class has just became a mess.

The overhead of reflection over polymorphism and switch is something like this:

time spent on a switch case call: 1
time spent on a polymorphism call: 1.1
time spent on a reflection call: 1.9-2.0

I benchmarked these guys a while ago, and those were my results, I don't have the code now because these benchmarks were done on my previous company and I don't have access to that code anymore.

Edison Gustavo Muenz
Great, that was exactly what I was searching for.Thanks a lot!
akappa
+1  A: 

I'm going to guess since you're talking about "messages" and "envelopes" that you're passing these messages over the wire. The time it takes to do that will absolutely dominate the extra time it takes for reflection. I've used reflection like this, and it's not a bad model.

GuyBehindtheGuy
Yes, but i'm using asynchronous I/O, so a single thread should process messages coming from a potentially huge set of connections, so with a good frequency.
akappa
Asynchronous I/O will definitely increase the number of messages you can handle, but it will do nothing to improve the performance of processing *one* message. As I stated, that will likely be dominated by the time spent sending the message over the wire or the time "processing" the message. Reflection will not make any difference. :-)
GuyBehindtheGuy
Mmh, the point is that, with Asynchronous I/O, write and read operations doesn't block, so I should not consider those times in the equation.Feel free to correct me if this reasoning is flawed ;)
akappa