Omry Zobel
Omry Zobel

Reputation: 853

Using Factory pattern with multiple arguments in Java

I have the following class structure: a base class 'Message' which contains some common members (/fields), 'Imessage' interface that has some methods that all messages should implement, a lot of different message classes that extends (inherits) the base 'Message' class and have a lot of fields, an enum for each message type and a factory class which given an enum creates an instance of the proper message class.

The issue is that I'm not sure where/how to implement the setting of values for each of the message classes. It can't be in it's constructor because in the factory method i need to build generic instances. Should i implement a 'Create' method for each of the messages that will set all of it's members?

    public static Message buildMessage(MessageType messageType)
        {
            Message message = null;
            switch (messageType) //TODO: add all messages!
            {
                case CONNECT: 
                    message = new ConnectMessage();
                    break;
                case CONNECT_RESPONSE: 
                    message = new ConnectResponseMessage();
                    break;  
                case DISCONNECT: 
                    message = new DisconnectMessage();
                    break;
                case FLOWSTART: 
                    message = new FlowStartMessage();
                    break;
                default: return null;
            }

            return message;
        }

Upvotes: 2

Views: 9246

Answers (3)

s.d
s.d

Reputation: 29436

If message definitions are rigid and you are not creating combinations of messages or configuring their properties, then why have a factory class ?

On another note, The enum alone is capable of much:

public class Main {

    public static interface IMessage{
        public String getName();
    }

    public static class GoodMessage implements IMessage{
        @Override
        public String getName() {
            return "Good";
        }
    }

    public static class BadMessage implements IMessage{
        @Override
        public String getName() {
            return "Bad";
        }
    }

    public static interface IMsgGen{
        public IMessage create();
    }

    public static enum Messages implements IMsgGen {

        GOOD_MSG(GoodMessage.class),

        BAD_MSG(BadMessage.class),

        CUSTOM_MSG(null){
            @Override
            public IMessage create() {
                return new IMessage() {
                    @Override
                    public String getName() {
                        return "Custom";
                    }
                };
            }
        };

        private final Class<? extends IMessage> mClass;
        private Messages(Class<? extends IMessage> aClass) {
            mClass = aClass;
        }

        @Override
        public IMessage create() {
            try {
                return mClass.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(),e);
            }
        }
    }

    public static void main(String[] args){
        IMessage msg = Messages.GOOD_MSG.create();
        System.out.println(msg.getName());

        msg = Messages.BAD_MSG.create();
        System.out.println(msg.getName());

        msg = Messages.CUSTOM_MSG.create();
        System.out.println(msg.getName());
    }
}

Upvotes: 0

Tot&#242;
Tot&#242;

Reputation: 1854

This is one possible solution. You can write a constructor in Message and override it in the subclasess.

public class Message {
    private final String commonField;

    public Message(String commonField){
        this.commonField = commonField;
    }
}

And in the subclassess

public ConnectMessage(String commonField){
    super(commonField);
    //initialize
}

And in the factory do

public static Message buildMessage(MessageType messageType, String commonValue)
        {
            Message message = null;
            switch (messageType) //TODO: add all messages!
            {
                case CONNECT: 
                    message = new ConnectMessage(commonValue);
                    break;
                case CONNECT_RESPONSE: 
                    message = new ConnectResponseMessage(commonValue);
                    break;  
                case DISCONNECT: 
                    message = new DisconnectMessage(commonValue);
                    break;
                case FLOWSTART: 
                    message = new FlowStartMessage(commonValue);
                    break;
                default: return null;
            }

            return message;
        }

Upvotes: 2

StuPointerException
StuPointerException

Reputation: 7267

The factory pattern should return a valid, fully populated object so adding a Create method for each type of Message object would not be ideal (unless it is called from within buildMessage).

I don't know what you mean when you say:

It can't be in it's constructor because in the factory method i need to build generic instances.

It's completely valid to initialise an objects like this:

Message message = new ComplexMessage(type, value, something, somethingElse);
Message message = new LessComplexMessage(type, value);

In which case your buildMessage method can take in all objects required to build all the sub types of your message.

If this becomes too complex because there are too many variations of required fields then it might be worth upgrading to the Builder Pattern:

http://javarevisited.blogspot.co.uk/2012/06/builder-design-pattern-in-java-example.html

Upvotes: 2

Related Questions