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.
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.
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.
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).
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.
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
}
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With