My question is to implement various behaviors for different messages as broadly as possible. I know about the visitor pattern, I know about double dispatch, but I cannot find a solution that satisfies me (not within java at least).
My situation is this:
I have a message hierarchy:

and a hierarchy of router interfaces, each of which defines a route method for its own message type:

which I would like to implement similarly to this:

to be able to add and remove the ability to route specific messages, and to easily change routing strategies for specific messages.
The problem is that without switching my message, which I don’t want to do, I cannot select the appropriate function for the interface, because something like
CompositeRouter comp = new AllRouter(...//new Router instances); MessageBase msg = new DerivedMessage(); msg.process(comp);
will select java overload <runtime message-type>.process(Router)
at compile time, which at run time is called for the corresponding router object. Therefore, I cannot select the correct process () calls at compile time. I also can't do it the other way around because comp.route(msg)
will be resolved to <dynamic router-type>.route(MessageBase) .
I could write a visitor who selects the correct method from CompositeRouter, but for this I would need to define a visitor interface with the appropriate route methods defined for all MessageTypes types in front, which type wins the target, because it means I have to rewrite the visitor whenever I add a new DerivedMessage.
Is there a way to implement this so that both Message and Router are extensible or is it hopeless given the current java functions?
Change 1:
Something I forgot to mention is that I have 4 or 5 other situations that pretty much match the Router hierarchy, so I seem to want to avoid Reflection for finding the method, because I'm afraid of the time consuming execution.
Reply to comments:
@aruisdante's assumption regarding @bot's suggestion is correct. I cannot redefine because I would lose the MessageBase runtime type if I redefine the route (MessageBase).
@aruisdante and @geceo: I know I can do this - this is what I meant with "switching" (MessageBase has a MessageType field) - but I have 11 actual message classes and ~ 6 locations in the code where I need it, so it will be a HUGE realization of pain as well as service wisely.