0
class PieceFactory {     
     @SuppressWarnings("rawtypes")
     public Piece createPiece(String pieceType) throws Throwable{
        Class pieceClass = Class.forName(pieceType);
        Piece piece = (Piece) pieceClass.newInstance();

         return piece;       
     }
}

私はまだ例外の処理に慣れていないので、例外をスローしているだけですが、このファクトリを使用するメソッドを使用するすべての場所で、throwableのような例外をスローする必要があると言われます。

たとえば、私のクラスの1つに、ファクトリを使用するメソッドを使用して多くのオブジェクトをインスタンス化するメソッドがあります。例外をスローするだけでそのクラスのメソッドを使用できますが、そのクラスへの参照を別のクラスに渡して、そこからメソッドを使用しようとすると機能しません。次に、例外をキャッチしようとします。

工場は必要ないかもしれませんが、面白そうだったので、型紙を使ってみたいと思います。ファクトリを作成した理由は、Pieceのサブクラスが6つあり、メソッドに引数として必要なサブクラスのタイプを渡すことによってそれらをインスタンス化するためにメソッドを使用したくないためです。

4

6 に答える 6

1

両方@SuppressWarningsthrows Throwable警報ベルを鳴らします。BlochによるEffectiveJavaを参照してください。

于 2011-01-13T14:52:00.400 に答える
1

反射的にオブジェクトを作成しようとしていPieceます。

Class.forName()をスローClassNotFoundExceptionし、Class.newInstance()InstantiationException、IllegalAccessExceptionをスローします(したがって、をスローする必要がありますThrowable

クラス型を介してオブジェクトを作成するためのより良い方法は、おそらく次のことを行うことです。

class PieceFactory {     

    public Piece createPiece(String pieceType) throws Throwable{
        Piece piece = null;

        if ("SubPiece1".equals(pieceType)) {
            piece = new SubPiece1();
        } else if ("SubPiece2".equals(pieceType)) {
            piece = new SubPiece2();
        }

        return piece;       
    }
}

PS、それはテストされておらず、それを行うためのより良い方法を示しているだけです。

お役に立てれば!:)

于 2011-01-13T14:53:54.280 に答える
1

throws ステートメントや try/catch ブロックをどこでも宣言したくない場合。

クラスを作成してクラスを拡張するか、それ自体または関連する拡張クラスRuntimeExceptionを使用します。RuntimeExceptionRuntimeException

次に、try-catch ブロックをルート (ファクトリ クラス メソッド) に配置し、スローされた例外をランタイム例外タイプ (上記のいずれか、選択したもの) にラップします。

ただし、それは本当に必要なものによって異なります。ある時点でまだ例外を処理する必要があります。そうしないと、アプリケーションが実行時に例外をスローし、それらを処理しないとアプリが期待どおりに動作しなくなります。

try{ 
    "your code which throws exception" 
} catch(ThrownExceptionType e){ 
   throw new RuntimrException(e);
}

例外を処理する必要があることに注意してください。これでうまくいくとは限りません。

于 2011-01-13T14:48:47.263 に答える
1

例外はどこかでキャッチする必要があります。私の理解が正しければ、このファクトリをラップするクラスが 1 つありますFactoryWrapper。コードのどこかでそのラッパー クラスを使用すると、例外をスローするかキャッチすることができます。これは、それを使用しているメソッドがある時点で (おそらく基本クラスで) try/catch ブロックで囲まれているためです。他の場所 (参照を渡す場所FactoryWrapper) は、例外をキャッチする必要がある最後の手段です (これは良い方法ではありませんが、決して呼び出されないメソッドである可能性があります)。

これは、他のクラスで例外をスローできない理由の単なる説明です。他の人がすでに述べたように、リフレクションを使用しないようにしてください。これは、他の選択肢よりもはるかに遅いためです。

1 つの抽象ファクトリを使用してから、型ごとに 1 つのファクトリを使用できます。詳細はこちらこちらをご覧ください。お役に立てれば。

編集 :

リフレクションについての興味深い記事がありますいつ使用するかについてのアイデアを提供します。

于 2011-01-13T15:01:04.277 に答える
1

例外ハンドラの作成に慣れることをお勧めします。そうでなければ、あなたの唯一の選択肢は、throwsすでに見たように、迷惑になり、困難を引き起こす宣言でコードをなぞることです。

この場合、メソッドの本体は、呼び出しからと呼び出しからClassNotFoundExceptionの2 つのチェック済み例外をスローできます 。forname()InstantiationExceptionnewInstance()

これらの最適な処理方法は、アプリケーションと好みによって異なります。別の回答で示唆されているように、1 つのオプションは単にそれらをキャッチして未チェックの例外をスローすることです。アプリケーションが完了すると、これらの例外が発生しないことが予想される場合、これは賢明です。これらの例外のいずれかが発生した場合、構成エラーを示している可能性が高いため、これがおそらくここで採用するアプローチです。

しかし、これらの例外が通常の使用法で合理的に発生する可能性があると考える理由がある場合は、それらをどのように処理するかを検討する必要があります。たとえば、Piece サブクラス名がユーザーによって GUI に入力された場合 (可能性は低いと思いますが、念のために言っておきます) ClassNotFoundException、名前のつづりが簡単に間違っている可能性があるため、a の可能性が高くなります。そのような状況では、このメソッドがその例外をスローできるようにし、呼び出し元がそれをキャッチして処理することを要求することが理にかなっている場合があります (たとえば、要求されたクラスが存在しないというメッセージをユーザーに返すことによって)。

于 2011-01-13T15:21:05.970 に答える
0

あなたのようにリフレクションを使用することは理想的ではありません。Piece クラスの名前を変更し、クライアントがハードコーディングされた完全修飾クラス名を渡すとすぐに、アプリが壊れます。Elite Gent の提案はその問題を回避しますが、それでもクライアントは具体的なクラスを知る必要があります。これはまさにファクトリ パターンが隠そうとするものです。私の意見では、列挙型を使用してピース型を表し、それをクライアントに引数としてファクトリ メソッドに渡すか、型ごとに個別のファクトリ メソッドを作成することをお勧めします (実行可能な 6 つのピース型を使用)。

とにかく先延ばしにしているので、列挙型アプローチの例を次に示します。

import java.util.ArrayList;
import java.util.List;

class PieceFactoryExample {

    static enum PieceFactory {
        ROOK {
            Piece create() {
                return new Rook();
            }
        };
        abstract Piece create();
    }

    static class Field {
        char line;
        int row;

        public Field(char line, int row) {
            this.line = line;
            this.row = row;
        }

        public String toString() {
            return "" + line + row;
        }
    }

    static interface Piece {

        void moveTo(Field field);

        List<Field> possibleMoves();
    }

    static abstract class AbstractPiece implements Piece {

        Field field;

        public void moveTo(Field field) {
            this.field = field;
        }
    }

    static class Rook extends AbstractPiece {

        public List<Field> possibleMoves() {

            List<Field> moves = new ArrayList<Field>();
            for (char line = 'a'; line <= 'h'; line++) {
                if (line != field.line) {
                    moves.add(new Field(line, field.row));
                }
            }
            for (char row = 1; row <= 8; row++) {
                if (row != field.row) {
                    moves.add(new Field(field.line, row));
                }
            }
            return moves;
        }
    }

    public static void main(String[] args) {

        Piece pawn = PieceFactory.ROOK.create();
        Field field = new Field('c', 3);
        pawn.moveTo(field);
        List<Field> moves = pawn.possibleMoves();
        System.out.println("Possible moves from " + field);
        for (Field move : moves) {
            System.out.println(move);
        }
    }
}

自己完結型の例を維持するために、ここではすべてを静的にしました。通常、Field、Piece、AbstractPiece、および Rook はトップレベルのモデル クラスであり、PieceFactory もトップレベルです。

これは、私が思うあなたの例に行くためのより良い方法であり、例外処理の問題を回避します。

それに戻ると、検討できるアプローチがいくつかあります(リフレクションアプローチに基づいて):

あなたが行ったように Throwable をスローすることは、すべてのエラーをひとまとめにし、クライアントにとってエラー処理が非常に面倒で不透明になるため、悪い習慣です。他に選択肢がない場合を除き、これを行わないでください。

チェックされたすべての例外に対して、メソッドで「スロー」を宣言します。これが有効かどうかを判断するには、スローしている例外の種類をクライアントが認識して理解する必要があるかどうかを検討してください。あなたの例では、Rook を作成したいクライアントは、リフレクション コードによってスローされた InstantiationException、IllegalAccessException、および ClassNotFoundException を知って理解する必要がありますか? おそらくこの場合ではありません。

クライアントがキャッチする必要のない実行時例外でそれらをラップします。これは必ずしも良い考えではありません。呼び出しているコードがチェック例外をスローしているという事実には、通常、理由があります。あなたの例では、リフレクションを行っていましたが、これは多くの点でうまくいかない可能性があります (API は LinkageError、ExceptionInInitializerError、ClassNotFoundException、IllegalAccessException、InstantiationException、および SecurityException を宣言します)。チェックされた例外を実行時例外にラップしても、その問題は解決しません。私はこれを「コードの匂い」だと考えています。エラーが回復不能なシステム障害を意味する場合、それは有効な選択かもしれませんが、ほとんどの場合、そのような障害をより適切に処理する必要があります。

完全なサブシステムに対してカスタム チェック例外をスローします。たとえば、すべての実装固有のデータ アクセス例外をラップするために使用される Spring の org.springframework.dao.DataAccessException を参照してください。これは、クライアントが 1 つの例外タイプだけをキャッチする必要があり、必要に応じて詳細を把握できることを意味します。あなたの場合、チェック済みの PieceCreationException を作成し、それを使用してすべての反射エラーをラップできます。これは有効な例外処理パターンですが、PieceFactory にとっては少し扱いに​​くいと思います。

null を返します。コード内のすべての例外をキャッチし、発生した場合は単純に null を返すことができます。JavaDoc にこれが明確に示されていることを確認してください。このアプローチの欠点は、クライアントがどこでも null をチェックしなければならない可能性があることです。

特定のエラー タイプを返します。これは、Java コア API で少し前に見た、こっけいな (非常にオブジェクト指向の) アプローチです (くそー、どこだったか思い出せません)。このために、追加の Piece タイプを作成します。

class NullPiece implements Piece {
    public void moveTo(Field field) {
        throw new UnsupportedOperationException("The Piece could not be created");
    }
    public List<Field> possibleMoves() {
        throw new UnsupportedOperationException("The Piece could not be created");
    }
}

作成中にエラーが発生した場合は、この型のインスタンスを返します。利点は、単純な null 値を返すよりも自己文書化できることですが、クライアントはもちろん のようなものを使用してこれを確認する必要がありますinstanceof。そうでない場合、Piece メソッドが呼び出されたときに UnsupportedOperationException がスローされます。少し重いですが、非常に明確です。ここまで行くかどうかはわかりませんが、それでも興味深いアイデアです。

于 2011-01-13T16:39:34.200 に答える