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
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
}
I'm pretty sure you just want to create a method on your enum type which will return the appropriate Question object. So anytime someone adds an enum value to QuestionType they will also have to update the method. Doesn't solve your problem of having to update that method though...
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();
}