views:

37

answers:

2

I'm looking for some ideas on implementing a basic message factory that reads a header from an input stream and creates the appropriate message type based on the type defined in the message header.

So I have something like (roughly.. and I'm willing to change the design if a better paradigm is presented here)

class MessageHeader { 
   public String type;
}

class MessageA extends Message {
   public static final String MESSAGE_TYPE = "MSGA";
   public MessageA (DataInputStream din) {
      var1 = din.readInt ();
      var2 = din.readInt ()
      // etc
   }
} 

and I essentially want to do something like this:

MessageHeader header = ... read in from stream.

if (header.type == MessageA.MESSAGE_TYPE) {
   return new MessageA (din);
} else if (header.type == MessageB.MESSAGE_TYPE) {
   return new MessageB (din);
}

Although this scheme works I feel like there could be a better method using a Map and an Interface somehow...

public interface MessageCreator {
  public Message create (DataInputStream);
}

Map <String, MessageCreater> factory = new Map <String, MessageCreator> ();
factory.put (MessageTypeA.MESSAGE_TYPE, new MessageCreator () { 
                          public Message create (DataInputStream din) {
                              return new MessageA (din); }});
...
// Read message header
Message createdMessage = Map.get (header.type).create (din);

But then whenever I want to use the message I have to use instanceof and cast to the correct subclass.

Is there a 3rd (better?) option? Maybe there's a way to accomplish this using templates. Any help is appreciated. Thanks

Edit: I guess it's important to note I want to "dispatch" the message to a function. So essentially I really want to do this:

MessageHeader header = ... read in from stream.

if (header.type == MessageA.MESSAGE_TYPE) {
   handleMessageA (new MessageA (din));
} else if (header.type == MessageB.MESSAGE_TYPE) {
   handleMessageB (new MessageB (din))
}

So a pattern that incorporates the factory and a dispatch would be perfect

A: 

just check all the typing on the modules

William Coleman
+1  A: 

How about letting the guy who creates the messages actually dispatch to a handler.

So you'd add a handler interface like this:

public interface MessageHandler {
    void handleTypeA(MessageA message);
    void handleTypeB(MessageB message);
}

Then you'd have a dispatcher which is basically the same thing as your MessageCreator, except it calls the correct method on the handler instead of returning the message object.

public interface MessageDispatcher {
    void createAndDispatch(DataInputStream input, MessageHandler handler);
}

The implementation is then almost identical to the first code snippet you posted:

public void createAndDispatch(DataInputStream input, MessageHandler handler) {
    MessageHeader header = ... read in from stream.

    if (header.type == MessageA.MESSAGE_TYPE) {
       handler.handleTypeA(new MessageA (din));
    } else if (header.type == MessageB.MESSAGE_TYPE) {
       handler.handleTypeB(new MessageB (din));
    }
}

Now you only have the one spot in the code where you have to do a switch or if/else if and after that everything is specifically typed and there's no more casting.

Mike Deck
Yeah I think I'll go with the simplistic switch approach. I'll only have 15-20 different types of messages. I think I wanted to do something fancy just for the sake of doing something cool... sometimes simpler is better
Shaun