Frage

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

         return piece;       
     }
}

ich alle Ausnahmen nicht verwendet Handhabung noch deshalb bin ich sie nur werfen, sondern überall, wo ich verwenden, um ein Verfahren, dass Nutzungen dieser Fabrik es mir, dass ich wie throwable werfen müssen Ausnahmen erzählt.

Zum Beispiel, in einen meiner Klassen habe ich eine Methode, die eine Menge von Objekten mit der Methode instanziiert, der die Fabrik verwendet. Ich kann die Methode in dieser Klasse verwenden, indem nur die Ausnahme zu werfen, aber es wird nicht funktionieren, wenn ich versuche, zu dieser Klasse in einer anderen Klasse eine Referenz zu übergeben und dann die Methode von dort zu verwenden. Dann zwingt er mich um die Ausnahme zu versuchen zu fangen.

Ich brauche wohl nicht eine Fabrik, aber es schien interessant und ich möchte Nutzungsmuster versuchen. Der Grund, warum ich das Werk geschaffen war, dass ich 6 Subklassen von Stück und ich wan't, ein Verfahren zu verwenden, um sie zu instanziiert durch die Art der Unterklasse vorbei I die Methode als Argument will.

War es hilfreich?

Lösung

Sie versuchen, ein Objekt Piece reflexiv zu erstellen.

Class.forName() wirft ClassNotFoundException, während Class.newInstance() wirft InstantiationException, Illegal (daher, warum Sie benötigen Throwable werfen.

Eine bessere Möglichkeit, ein Objekt durch Klassentypen zu erstellen, ist wahrscheinlich, indem Sie die folgenden Schritte aus:

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 , es ist nicht getestet, nur eine bessere Art und Weise zeigt, es zu tun.

Hope, das hilft! :)

Andere Tipps

Beide @SuppressWarnings und throws Throwable Ring Alarmglocken. Siehe Effective Java von Bloch.

Wenn Sie declare wirft Aussagen oder try / catch-Block überall nicht wollen.

Erstellen Sie eine Klasse und RuntimeException Klasse erweitern oder Verwendung RuntimeException selbst oder verwandte RuntimeException erstreckt Klassen.

Dann Ort try-catch-Block an die Wurzel (Ihre Fabrik Klassenmethoden) und die Ausnahmen wickeln eine Runtime Ausnahmetyp geworfen in (einer von oben, je nachdem, was Sie wählen).

Doch es hängt wirklich davon ab, was Sie brauchen. Irgendwann werden Sie noch brauchen, um Griff Ausnahmen oder Ihre Anwendung Ausnahme zur Laufzeit werfen und App würde nicht das tun, was erwartet wurde, wenn Sie nicht mit ihnen umgehen.

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

Bitte beachten Sie immer noch die Ausnahme behandeln müssen. Es bedeutet nicht, das wird Arbeit alles gut.

müssen Ausnahmen irgendwo gefangen werden. Wenn ich das richtig verstanden eine Klasse, die Sie haben, um dieses Werk gewickelt ist, sagen wir ein FactoryWrapper. Irgendwo in Ihrem Code verwenden Sie diese Wrapper-Klasse und Sie können Sie Ausnahme entweder werfen oder zu fangen, weil das Verfahren, in dem Sie es verwenden wahrscheinlich irgendwann (in einer Basisklasse wahrscheinlich) durch einen try / catch-Block während der umgeben ist vor anderen (an dem Sie Ihre FactoryWrapper Referenz sind vorbei) ist wahrscheinlich ein letztes Mittel (es ist keine gute Praxis, aber es könnte ein Verfahren sein, das nie genannt wird), wo die Ausnahme Notwendigkeit gefangen werden.

Dies ist nur eine mögliche Erklärung, warum Sie nicht die Ausnahme in der anderen Klasse werfen. Wie andere bereits erwähnt haben, nicht versuchen, mithilfe von Reflektion, weil so viel langsamer als die anderen Alternativen ist.

Sie könnten eine abstrakte Fabrik verwenden und dann eine Fabrik für jeden Typ. Details sehen hier und hier . Hoffe, das hilft.

EDIT:

Hier ist ein interessanter Artikel über Reflexion. Es wird Ihnen eine Idee geben, wenn es zu benutzen.

Ich empfehle, dass Sie mit dem Schreiben von Exception-Handler auf immer bequem arbeiten. Ansonsten ist Ihre einzige Option Code mit throws Erklärungen zu durchlöchern, die Schwierigkeiten ärgerlich und Ursachen werden, wie Sie bereits gesehen haben.

In diesem Fall kann der Körper Ihrer Methode wirft zwei Ausnahmen geprüft. ClassNotFoundException vom forname() Anruf und InstantiationException vom newInstance() Anruf

Wie man am besten Griff diese hängt von Ihrer Anwendung und Ihren Wünschen. Wie durch eine andere Antwort vorgeschlagen, ist eine Option, einfach, sie zu fangen und unkontrolliert Ausnahmen zu werfen. Dies ist sinnvoll, wenn Sie erwarten, dass diese Ausnahmen sollten niemals auftreten, wenn der Antrag vollständig ist. Dies ist wahrscheinlich der Ansatz, den ich würde hier nehmen, denn wenn eine dieser Ausnahmen aufgetreten es wahrscheinlich einen Konfigurationsfehler hinweisen.

Aber wenn Grund diese Ausnahmen zu denken, angemessen im normalen Gebrauch auftreten können, sollten Sie darüber nachdenken, wie Sie wollen, dass sie behandeln. So wurden zum Beispiel wenn das Stückes Unterklasse Namen in eine GUI von einem Benutzer eingegeben werden (nicht wahrscheinlich, ich weiß, aber nur um den Punkt zu machen), dann ein ClassNotFoundException viel mehr wird wahrscheinlich, da der Name leicht falsch geschrieben werden kann. In dieser Situation ist es sinnvoll, dieser Methode zu ermöglichen, diese Ausnahme zu werfen, und erfordert die Anrufer zu fangen und zu handhaben es (zum Beispiel durch eine Nachricht zurück an den Benutzer, dass die angeforderte Klasse nicht existiert).

Reflexion verwenden wie Sie tun, ist nicht ideal. Sobald Sie ein Stück Klasse umbenennen und Kunden voll qualifizierte Klassennamen Pass fest einprogrammiert, wird Ihre App brechen. Die Elite Gent Vorschlag vermeidet dieses Problem, aber immer noch erfordert Kunden die konkrete Klasse zu wissen, was genau das ist, was die Fabrik Muster versucht zu verstecken. Ein besserer Ansatz meiner Meinung nach würde entweder eine ENUM verwenden, um Stück Typen zu repräsentieren und die Client verstreichen lassen, dass als Argument für Ihre Factory-Methode, oder für jede Art (mit 6 Stück Typen, die machbar sind) getrennte Fabrik Methoden erstellen.

Da ich zaudere trotzdem, hier ein Beispiel für den ENUM-Ansatz:

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

habe ich alles statisch hier das Beispiel umluftunabhängigem zu halten. Normalerweise Field, Piece, AbstractPiece und Rook würden Top-Level-Modellklassen und PieceFactory würde auch auf höchster Ebene sein.

Dies ist eine bessere Art und Weise für Ihr Beispiel zu gehen denke ich, und vermeidet die Ausnahmebehandlung Problem.

Rückkehr zu dem, es gibt ein paar Ansätze können Sie (auf der Grundlage Ihrer Reflexion Ansatz) betrachten:

Throwable Werfen wie Sie haben, ist eine schlechte Praxis, da es Klumpen zusammen alle Fehler und macht die Fehlerbehandlung sehr umständlich und intransparent für die Kunden. Tun Sie das nicht, wenn Sie keine anderen Optionen haben.

Declare ‚wirft‘ auf Ihrer Methode für alle geprüften Ausnahmen. Um zu entscheiden, ob diese gültig ist, prüfen, ob der Client sollte wissen und verstehen, die Art Ausnahme Sie werfen. In Ihrem Beispiel sollte der Kunde die von Ihrem Reflexion Code geworfen ein Rook kennen und verstehen die InstantiationException, Illegal und ClassNotFoundException schaffen will? Wahrscheinlich nicht in diesem Fall.

wickeln sie in einer Runtime-Ausnahme, die von den Kunden aufgefangen werden muss nicht. Dies ist nicht immer eine gute Idee. Die Tatsache, dass Code, den Sie anrufen, ist das Werfen geprüfte Ausnahmen in der Regel einen Grund hat. In Ihrem Beispiel Sie Reflexion taten, und dies kann in vielerlei Hinsicht falsch machen (die API erklärt LinkageError, ExceptionInInitializerError, ClassNotFoundException, Illegal, InstantiationException und Security). hat die geprüfte Ausnahmen in einer Runtime-Ausnahme Wrapping nicht dieses Problem weggehen. Ich halte, dies zu tun ein ‚Codegeruch‘. Wenn der Fehler einen nicht behebbaren Systemausfall bedeutet, dann könnte es eine gültige Wahl sein, aber in den meisten Fällen würden Sie solche Fehler eleganter handhaben wollen.

Werfen Sie eine benutzerdefinierte geprüfte Ausnahme für ein komplettes Subsystem. Siehe zum Beispiel Spring org.springframework.dao.DataAccessException die verwendet wird, alle Implementierung spezifischen Datenzugriff Ausnahmen zu wickeln. Diese Mittel Kunden haben nur eine Ausnahmetyp zu fangen und können die Details herausfinden, wenn sie müssen. In Ihrem Fall könnten Sie erstellen PieceCreationException geprüft und dass alle die Reflexionsfehler wickeln verwenden. Dies ist eine gültige Ausnahmemuster Handhabung, aber ich denke, es könnte für Ihre PieceFactory ein wenig zu plump sein.

Return null. Sie könnten alle Ausnahmen in Ihrem Code fangen und einfach null zurück, wenn sie auftreten. So stellen Sie sicher, dass Ihre JavaDoc deutlich zeigt dies an. Ein Nachteil dieses Ansatzes ist, dass Kunden für nulls überall haben könnten zu überprüfen.

Zurück ein bestimmte Fehlertyp. Dies ist ein geeky (sehr objektorientiert) Ansatz, den ich sehe in dem Java-Kern-API irgendwo eine Weile zurück (darn, kann sich nicht erinnern, wo). Dazu würden Sie ein zusätzliches Stück Typ erstellen:

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

Und gibt eine Instanz dieses Typs, wenn ein Fehler bei der Erstellung auftritt. Der Vorteil ist, dass es selbsterklärend ist als einen einfachen Null-Wert zurück, aber Kunden würde natürlich müssen für dieses mit so etwas wie instanceof ist. Wenn sie dies nicht tun, dann werden sie die UnsupportedOperationException geworfen denen die Piece Methoden aufgerufen werden. Ein bisschen schwer, aber sehr deutlich. Ich bin sicher nicht, dass ich so weit gehen würde, aber es ist immer nocheine interessante Idee.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top