Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

augment the factory pattern in java

I am trying to use a factory pattern to create a QuestionTypeFactory where the instantiated classes will be like MultipleChoice, TrueFalseQuestion etc.

The factory code looks something like this

class QuestionFactory {
    public enum QuestionType {
        TrueFalse,
        MultipleChoice,
        Essay
    }

public static Question createQuestion(QuestionType quesType) {
    switch (quesType) {
        case TrueFalse:
            return new TrueFalseQuestion();
        case MultipleChoice:
            return new MultipleChoiceQuestion();
        case Essay:
            return new EssayQuestion();
    }
    throw new IllegalArgumentException("Not recognized.");
}
}

This works ok for now. If I want to add another question type I will need to modify the factory class and I do not want to do that.

How can I set it up so that each question class registers itself with the Factory so that when I add a new question type, I do not have to change the code for the factory? I am a bit new to java and am not sure how to do this.

Edit

Additional Information

All the question classes implement an IQuestion interface. I am looking for a way to implement a method like

public static void registerType(QuestionType quesType, Class<IQuestion> ques)

so that I can call this method from a static block from my classes so that when I add a new question type, I will not have to change or add any code in the Question Factory. I know I would have to change the current implementation to make it generic. I am not sure the method that I wrote above is correct in terms of its arguments syntactically or not but it shows what I want in concept.

like image 635
randomThought Avatar asked Apr 06 '10 02:04

randomThought


People also ask

What is the factory design pattern in Java?

The factory design pattern says that define an interface ( A java interface or an abstract class) for creating object and let the subclasses decide which class to instantiate. The factory method in the interface lets a class defers the instantiation to one or more concrete subclasses.

What problem is solved by factory pattern in Java?

Factory method is a creational design pattern which solves the problem of creating product objects without specifying their concrete classes. The Factory Method defines a method, which should be used for creating objects instead of using a direct constructor call ( new operator).

What is the advantage of factory design pattern in Java?

Advantage of Factory Design Pattern Factory Method Pattern allows the sub-classes to choose the type of objects to create. It promotes the loose-coupling by eliminating the need to bind application-specific classes into the code.


2 Answers

You can probably do that with the register method you've shown, through the Reflection API (that Class thingy).

I am not proficient enough with Java Reflection to write a more helpful answer, but if you look for some getConstructor method or something you'll probably get there.

To call that method you should do something like (note the .class syntax):

QuestionFactory.registerType(QuestionType.TrueFalse, TrueFalseQuestion.class);

EDIT Ah, whatever, I have the time to investigate. Try this:

public class QuestionFactory {
    static final Map<QuestionType, Constructor<? extends Question>> map =
        new HashMap<QuestionType, Class<? extends Question>>();

    public static void registerType(QuestionType quesType, Class<? extends Question> ques) {
        map.put(quesType, ques.getConstructor());
    }

    public static Question createQuestion(QuestionType quesType) {
        return map.get(quesType).newInstance();
    }
}

I haven't compiled this, but it should work, or at least guide you in the right direction. For this to work the Question implementations must have a constructor without arguments.

Because you're using a static factory (aka, object-oriented global variables) you can make questions register themselves in their static initializer.

public class TrueFalseQuestion implements Question {
    static {
        QuestionFactory.registerType(QuestionType.TrueFalse, TrueFalseQuestion.class);
    }
    // Whatever else goes here
}
like image 61
R. Martinho Fernandes Avatar answered Sep 24 '22 20:09

R. Martinho Fernandes


One possibility:

public enum QuestionType {
    TrueFalse(TrueFalseQuestion.class),
    MultipleChoice(MultipleChoiceQuestion.class),
    Essay(EssayQuestion.class)

    private final Class<? extends Question> implementationType;
    QuestionType(Class<? extends Question> implementationType) {
       this.implementationType = implementationType;
    }

    public Question createQuestion() { 
       return implementationType.newInstance(); 
    }
}

Of course, this gets rid of the factory and assumes all your questions have no-args constructors, but as far as I can tell, it covers all the cases of the code sketch above. If construction for the particularly classes is more complicated, you can always setup something like:

public enum QuestionType {
    TrueFalse { public Question createQuestion() { /* construction logic goes here */ } }
    public abstract Question createQuestion();
}
like image 33
ig0774 Avatar answered Sep 23 '22 20:09

ig0774