Pregunta

Estoy intentando utilizar un patrón de fábrica para crear un QuestionTypeFactory donde las clases instanciadas serán como opción múltiple, TrueFalseQuestion etc.

El código de fábrica miradas algo como esto

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.");
}
}

Esto funciona bien por ahora. Si quiero añadir otro tipo de pregunta que tendrá que modificar la clase de fábrica y no quiero hacer eso.

¿Cómo puedo configurarlo de manera que cada pregunta se registra la clase de fábrica con el fin de que cuando agrego un nuevo tipo de pregunta, que no tienen que cambiar el código de la fábrica? Soy un poco nuevo en java y no estoy seguro de cómo hacer esto.

Editar

Información adicional

Todas las clases de preguntas implementar una interfaz IQuestion. Estoy buscando una manera de poner en práctica un método como

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

para que pueda llamar a este método desde un bloque estático de mis clases para que cuando agrego un nuevo tipo de pregunta, no voy a tener que cambiar o añadir cualquier código en la pregunta de fábrica. Sé que tendría que cambiar la implementación actual para que sea genérico. No estoy seguro de que el método que escribí arriba es correcta en términos de sus argumentos sintácticamente o no, pero se nota lo que quiero en el concepto.

¿Fue útil?

Solución

Probablemente puede hacer eso con el método de registro que has demostrado, a través de la API de reflexión (que cosita Class).

No soy lo suficientemente hábil con la reflexión de Java para escribir una respuesta más útil, pero si se mira desde hace algún método getConstructor o algo es probable que llegue.

Para llamar a ese método que debe hacer algo como (tenga en cuenta la sintaxis .class):

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

Editar Ah, lo que sea, tengo el tiempo para investigar. Prueba esto:

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();
    }
}

No he recopilado esta, pero debería funcionar, o al menos le guiará en la dirección correcta. Para que esto funcione las implementaciones cuestión debe tener un constructor sin argumentos.

Debido a que usted está utilizando una fábrica estática (aka, orientado a objetos variables globales) se puede hacer preguntas registran a sí mismos en su estática inicializador .

public class TrueFalseQuestion implements Question {
    static {
        QuestionFactory.registerType(QuestionType.TrueFalse, TrueFalseQuestion.class);
    }
    // Whatever else goes here
}

Otros consejos

Una posibilidad:

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(); 
    }
}

Por supuesto, esto se deshace de la fábrica y asume todas sus preguntas no tienen-args constructores, pero por lo que puedo decir, que cubre todos los casos del boceto código de seguridad. Si la construcción de las clases en particular es más complicado, siempre se puede configurar algo como:

public enum QuestionType {
    TrueFalse { public Question createQuestion() { /* construction logic goes here */ } }
    public abstract Question createQuestion();
}

Estoy bastante seguro de lo que desea es crear un método en el tipo de enumeración que devolverá el objeto pregunta apropiada. Así que cada vez que alguien añade un valor de enumeración a QuestionType también tendrán que actualizar el método. No resuelve el problema de tener que actualizar ese método, aunque ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top