увеличить фабричный образец в Java - PullRequest
4 голосов
/ 06 апреля 2010

Я пытаюсь использовать шаблон фабрики для создания QuestionTypeFactory, где экземпляры классов будут похожи на MultipleChoice, TrueFalseQuestion и т. Д.

Заводской код выглядит примерно так

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

Пока все работает нормально. Если я хочу добавить другой тип вопроса, мне нужно будет изменить класс фабрики, и я не хочу этого делать.

Как я могу настроить его так, чтобы каждый класс вопросов регистрировался в Factory, чтобы при добавлении нового типа вопроса мне не приходилось менять код для фабрики? Я немного новичок в Java и не знаю, как это сделать.

Редактировать

Дополнительная информация

Все классы вопросов реализуют интерфейс IQuestion. Я ищу способ реализовать такой метод, как

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

чтобы я мог вызывать этот метод из статического блока из моих классов, чтобы при добавлении нового типа вопроса мне не приходилось изменять или добавлять какой-либо код в фабрике вопросов. Я знаю, что мне придется изменить текущую реализацию, чтобы сделать ее общей. Я не уверен, что метод, который я написал выше, является верным с точки зрения синтаксических аргументов или нет, но он показывает то, что я хочу в концепции.

Ответы [ 3 ]

6 голосов
/ 06 апреля 2010

Вы, вероятно, можете сделать это с помощью метода register, который вы показали, через Reflection API (это Class штука).

Я недостаточно опытен с Java Reflection, чтобы написать более полезный ответ, но если вы ищете какой-то метод getConstructor или что-то еще, вы, вероятно, получите его.

Чтобы вызвать этот метод, вы должны сделать что-то вроде (обратите внимание на синтаксис .class):

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

РЕДАКТИРОВАТЬ Ах, что угодно, у меня есть время для расследования. Попробуйте это:

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

Я не скомпилировал это, но это должно сработать или, по крайней мере, направить вас в правильном направлении. Чтобы это работало, реализации Вопроса должны иметь конструктор без аргументов.

Поскольку вы используете статическую фабрику (иначе говоря, объектно-ориентированные глобальные переменные), вы можете задавать вопросы самостоятельно в их статическом инициализаторе .

public class TrueFalseQuestion implements Question {
    static {
        QuestionFactory.registerType(QuestionType.TrueFalse, TrueFalseQuestion.class);
    }
    // Whatever else goes here
}
2 голосов
/ 06 апреля 2010

Одна возможность:

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

Конечно, это избавляет от фабрики и предполагает, что все ваши вопросы имеют конструкторы без аргументов, но, насколько я могу судить, он охватывает все случаи из приведенного выше наброска кода. Если конструкция для конкретных классов более сложная, вы всегда можете настроить что-то вроде:

public enum QuestionType {
    TrueFalse { public Question createQuestion() { /* construction logic goes here */ } }
    public abstract Question createQuestion();
}
0 голосов
/ 06 апреля 2010

Я почти уверен, что вы просто хотите создать метод для вашего типа enum, который будет возвращать соответствующий объект Question.Поэтому каждый раз, когда кто-то добавляет значение типа enum в QuestionType, ему также необходимо обновить метод.Однако не решает проблему обновления этого метода ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...