0

I'm hoping someone can give some guidance on an issue I'm having. I have:

  • A WebSocket service, where I have a single method on the server that handles all traffic.
  • Lots of different kinds of messages, each message has a "type" and we select which handler class to use based off that value.

In the HTTP world I would have a different method for each message type by creating a "message routing" configuration, i.e. I would assume the URL itself would contain the route to the correct method to use for the message I was sending. e.g. GET service.com/{serviceName}/{method}.

In the websocket world I don't have that luxury, we can only afford a single websocket per client, and all messages from that client will be sent to a single method, in our case onPost. Now, I still want to be able to specify which method/class should handle that message, but I don't know what pattern I should be using to achieve that.

The best I've come up with so far is to use the Service Locator pattern, whereby I would locate the correct handler on-the-fly. Something similar to this pseudo-code (off the top of my head here..):

interface IHandler{

    String forMessageType;
    void ProcessMessage(message);
}

class HandlerNumberOne implements IHandler{

    String forMessageType = "messageTypeOne";

    void ProcessMessage(message){ ... }
}

class HandlerLocator{

    static List<IHandler> handlers = Container.ResolveAll<IHandler>();

    static IHandler getByMessageType(String messageType){
        return handlers.First(h=>h.forMessageType == messageType);
    }
}

I would then use that locator in the onPost method like this:

class Service{

    void onPost(Message msg){

        IHandler handler = HandlerLocator.getByMessageType(msg.MessageType);
        handler.ProcessMessage(msg);
    }
}

My fellow comrades have thrown this to the fire, as they consider Service Locator a serious anti-pattern because "it hides dependencies". However, the desire to remove the (currently) 16 handler class dependencies we have injected into our Service constructor is leading me to grasp at pretty much anything to solve the issue.

  • Are there any plugins for message routing with webockets that I'm missing? I would love to be able to send a message to a URL path and have it handled by a unique method automagically.
  • (My main question:) Are there any well known patterns I've missed that would solve our woes?
  • Why is service locator pattern any worse than message routing? It seems to me that routing a message to a method in a service based on a path value is exactly what service locator pattern is, am I wrong about that?

EDIT: I believe this question is different to this one because I'm asking about a specific scenario and for a preferable pattern to use, whereas the linked question is asking "how to make a decision about which pattern to use" in a much, much broader sense.

  • 2
    Possible duplicate of Choosing the right Design Pattern – gnat Feb 19 at 18:44
  • @gnat Can you explain why you think that linked question is a duplicate of this one? I thought I was clearly asking for a specific use case scenario, whereas the linked question is very, very broad. Have I missed something? – Dan Rayson Feb 19 at 21:38
  • @DanRayson: gnat often votes for questionable duplicates, and is quite resistable against any critics. However, the word "pattern" is a buzzword for many people here, and if you want your question to be saved, just replace "pattern" by "approach", then it becomes more clearer that you are not asking for some kind of a braindead GoF pattern. – Doc Brown Mar 2 at 15:50
3

Your use of the service locator is fine.

Your comrades probably heard "service Locator is an anti-pattern" without understanding the context. A service locator should not be used when dependency injection is more appropriate. But you can't really use dependency injection to locate a handler at runtime, so that is not a relevant objection here.

You can probably register each handlers under a name and then resolve it using this name, like Container.Resolve<IHandler>(messageType); this will simplify your code a bit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.