5

ファクトリパターンを使用して、インスタンス化されたクラスがMultipleChoice、TrueFalseQuestionなどのようなQuestionTypeFactoryを作成しようとしています。

ファクトリコードは次のようになります

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

これは今のところ問題なく動作します。別の質問タイプを追加したい場合は、ファクトリクラスを変更する必要がありますが、変更したくありません。

新しい質問タイプを追加するときにファクトリのコードを変更する必要がないように、各質問クラスがファクトリに登録されるように設定するにはどうすればよいですか?私はJavaに少し慣れていないので、これを行う方法がわかりません。

編集

追加情報

すべての質問クラスはIQuestionインターフェースを実装しています。私は次のようなメソッドを実装する方法を探しています

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

これにより、クラスの静的ブロックからこのメソッドを呼び出すことができるため、新しい質問タイプを追加するときに、質問ファクトリでコードを変更または追加する必要がなくなります。現在の実装を汎用化するために変更する必要があることはわかっています。上で書いた方法が構文的に引数の点で正しいかどうかはわかりませんが、概念的には何が欲しいかを示しています。

4

3 に答える 3

6

おそらく、Reflection APIを介して、示したregisterメソッドを使用してそれを行うことができます(それはClass重要です)。

私はJavaReflectionに精通していないため、より役立つ回答を書くことができませんが、何らかの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();
    }
}

私はこれを編集していませんが、うまくいくか、少なくとも正しい方向にあなたを導くはずです。これが機能するためには、Questionの実装に引数のないコンストラクターが必要です。

静的ファクトリ(別名、オブジェクト指向のグローバル変数)を使用しているため、質問を静的初期化子に登録させることができます。

public class TrueFalseQuestion implements Question {
    static {
        QuestionFactory.registerType(QuestionType.TrueFalse, TrueFalseQuestion.class);
    }
    // Whatever else goes here
}
于 2010-04-06T03:02:15.167 に答える
2

1つの可能性:

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();
}
于 2010-04-06T03:09:09.127 に答える
0

適切なQuestionオブジェクトを返すenum型のメソッドを作成したいだけだと確信しています。したがって、誰かがQuestionTypeに列挙値を追加するたびに、メソッドも更新する必要があります。ただし、そのメソッドを更新する必要があるという問題は解決しません...

于 2010-04-06T02:44:30.747 に答える