C# Dispatch – Dynamic Dispatch Overuse

cdispatch

I was going through old code and noticed one pattern that repeats itself all over the place – dynamic dispatch.

While I don't see any problem with the implementation itself, I was wondering if there are other ways of handling dynamic dispatch.

To bring an example – consider a scenario where at run time I'm going to get a message – either Customer or Visitor and perform some operation based on the type of the message. For the sake of brevity let's say all we need to do is to print out a corresponding message type.

So to go from words to code

public abstract class Message
{
   public abstract string Id {get;}
}

public class Customer: Message
{
   public override string Id {get {return "Customer";}}
}

public class Visitor: Message
{
   public override string Id {get {return "Visitor";}}
}

And handling part

public interface IHandleMessage
{
  bool CanHandle(Message message);
  void Handle(Message message);
}

public class CustomerHandler: IHandleMessage
{
   public bool CanHandle(Message message)
   {
      return message.Id == "Customer";
   }

   public void Handle(Message message) {Console.WriteLine(message.Id);}
}

public class VisitorHandler: IHandleMessage
{
   public bool CanHandle(Message message)
   {
      return message.Id == "Visitor";
   }

   public void Handle(Message message) {Console.WriteLine(message.Id);}
}

public class MessageHandlersFactory
{
   private static readonly IEnumerable<IHandleMessage> _messageHandlers =
       new List<IHandleMessage> {new CustomerHandler(), new VisitorHandler()};

   public static IHandleMessage GetHandlerForMessage(Message message)
   {
       return _messageHandlers.FirstOrDefault(h => h.CanHandle(message));
   }
}

And the client code looks like this

public class Program
{
   public static void Main(Message message)
   {
      IHandleMessage handler = MessageHandlersFactory.GetHandlerForMessage(message);

      handler.Handle(message)
   }
}

Now as I said, I don't mind this implementation, what I really don't like is this pattern repeats itself all over the place, which makes me think if this is not an overuse of dynamic dispatch.

To generalize – everywhere where decision has to be made based on incoming message/data/argument I do have more or less the same implementation as I provided above.

So my question is – given example above is there other ways of handling this kind of scenarios ? Or this is recommended and accepted way of dealing with dynamic dispatch?

Best Answer

One could get rid of the CanHandle() method and simply use a dictionary where the key is the message Id. That would be simple and clean.

If the handling logic becomes more complex or if multiple handlers can be invoked for a particular message, then CanHandle() serves a better purpose.

But it seems from your example that only a single handler for each message is needed, so a dictionary of handlers would suffice. The factory could use the internal dictionary and return the correct handler class based on key (id).