Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design pattern for handling multiple message types

I've got the GOF sitting on my desk here and I know there must be some kind of design pattern that solves the problem I'm having, but man I can't figure it out.

For simplicities sake, I've changed the name of some of the interfaces that I'm using.

So here's the problem, on one side of the wire, I've got multiple servers that send out different types of messages. On the other side of the wire I have a client that needs to be able to handle all the different types of messages.

All messages implement the same common interface IMessage. My problem is, when the client gets a new IMessage, how does it know what type of IMessage its received?

I supposed I could do something like the following, but this just FEELS awful.

TradeMessage tMessage = newMessage as TradeMessage; if (tMessage != null) {     ProcessTradeMessage(tMessage); }  OrderMessage oMessage = newMessage as OrderMessage; if (oMessage != null) {     ProcessOrderMessage(oMessage); } 

The second thought, is to add a property to IMessage called MessageTypeID, but that would require me to write something like the following, which also FEELS awful.

TradeMessage tMessage = new TradeMessage(); if (newMessage.MessageTypeID == tMessage.MessageTypeID) {     tMessage = newMessage as TradeMessage;     ProcessTradeMessage(tMessage);  }  OrderMessage oMessage = new OrderMessage(); if (newMessage.MessageTypeID == oMessage.MessageTypeID) {     oMessage = newMessage as OrderMessage;     ProcessOrderMessage(oMessage); } 

I know this general problem has been tackled a million times, so there has to be a nicer way of solving the problem of having a method that takes an interface as a parameter, but needs different flow control based on what class has implemented that interface.

like image 887
Jonathan Beerhalter Avatar asked Sep 25 '09 14:09

Jonathan Beerhalter


2 Answers

You could create separate message handlers for each message type, and naively pass the message to each available handler until you find one that can handle it. Similar to the chain of responsibility pattern:

public interface IMessageHandler {     bool HandleMessage( IMessage msg ); }  public class OrderMessageHandler : IMessageHandler {     bool HandleMessage( IMessage msg ) {        if ( !(msg is OrderMessage)) return false;         // Handle the message and return true to indicate it was handled        return true;      } }  public class SomeOtherMessageHandler : IMessageHandler {     bool HandleMessage( IMessage msg ) {        if ( !(msg is SomeOtherMessage) ) return false;         // Handle the message and return true to indicate it was handled        return true;     } }  ... etc ...  public class MessageProcessor {     private List<IMessageHandler> handlers;      public MessageProcessor() {        handlers = new List<IMessageHandler>();        handlers.add(new SomeOtherMessageHandler());        handlers.add(new OrderMessageHandler());     }      public void ProcessMessage( IMessage msg ) {        bool messageWasHandled        foreach( IMessageHandler handler in handlers ) {            if ( handler.HandleMessage(msg) ) {                messageWasHandled = true;                break;            }        }         if ( !messageWasHandled ) {           // Do some default processing, throw error, whatever.        }     } } 

You could also implement this as a map, with the message class name or message type id as a key and the appropriate handler instance as the value.

Others have suggested having the message object "handle" itself, but that just doesn't feel right to me. Seems like it would be best to separate the handling of the message from the message itself.

Some other things I like about it:

  1. You can inject the message handlers via spring or what-have-you rather than creating them in the constructor, making this very testable.

  2. You can introduce topic-like behavior where you have multiple handlers for a single message by simply removing the "break" from the ProcessMessage loop.

  3. By separating the message from the handler, you can have different handlers for the same message at different destinations (e.g. multiple MessageProcessor classes that handle the same messages differently)

like image 151
Eric Petroelje Avatar answered Sep 19 '22 11:09

Eric Petroelje


A couple of solutions are applicable for this, first is best solution, last is least best. All examples are pseudocode:

1st, and best solution

Vincent Ramdhanie introduced the actual correct pattern to solve this problem, which is called the strategy pattern.

This pattern creates a separate 'processor', in this case to process the messages accordingly.

But I'm pretty sure a good explanation is given in your book by the GOF :)

2nd

As commented, the message may not be able to process itself, it is still usefull to create an interface for the message, or a base class, so you can make a general processing function for a message, and overload it for more specific ones.

overloading is in any case better then creating a different method for every type of message...

public class Message {} public class TradeMessage extends Message {}  public class MessageProcessor {     public function process(Message msg) {         //logic     }      public function process(TradeMessage msg) {         //logic     } } 

3rd

If your message could process itself you could write an interface, since your process method depends on what message you got, it seems easier to put it inside the message class...

public interface IMessage {     public function process(){} } 

you then implement this in all your message classes and proccess them:

list = List<IMessage>(); foreach (IMessage message in list) {     message.process(); } 

in your list you can store any class that implements that interface...

like image 39
NDM Avatar answered Sep 19 '22 11:09

NDM