Domanda

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

         return piece;       
     }
}

Non sto tutto utilizzato per la gestione delle eccezioni ancora quindi sto solo gettarli, ma ovunque io uso un metodo che utilizza questa fabbrica mi devo buttare eccezioni come Throwable dice.

Per esempio, in una delle mie classi ho un metodo che crea un'istanza di un sacco di oggetti utilizzando il metodo che utilizza la fabbrica. Posso utilizzare il metodo di quella classe semplicemente gettando eccezione, tuttavia non funziona se si tenta di passare un riferimento a tale classe ad un'altra classe e quindi utilizzare il metodo da lì. Poi mi costringe a provare intercettare l'eccezione.

Probabilmente non hanno bisogno di una fabbrica, ma è sembrato interessante e mi piacerebbe provare a modelli di consumo. La ragione per cui ho creato la fabbrica era che ho 6 sottoclassi di pezzo e io wan't di utilizzare un metodo per creare un'istanza di loro passando il tipo di sottoclasse che voglio come argomento del metodo.

È stato utile?

Soluzione

Si sta tentando di creare un oggetto riflessivo Piece.

Class.forName() getta ClassNotFoundException, mentre Class.newInstance() getta InstantiationException, IllegalAccessException (da qui il motivo per cui è necessario gettare Throwable.

Un modo migliore per creare un oggetto attraverso tipi di classe è probabilmente nel modo seguente:

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 , è testato, solo mostrando un modo migliore per farlo.

Spero che questo aiuti! :)

Altri suggerimenti

Entrambi i campanelli d'allarme anello @SuppressWarnings e throws Throwable. Vedere Effective Java da Bloch.

Se non volete dichiarare getta dichiarazioni o provare / blocco catch in tutto il mondo.

Creare una classe ed estendere classe RuntimeException o uso sé RuntimeException o correlato RuntimeException estendere le classi.

Poi blocco posto try-catch alla radice (i vostri metodi di classe di fabbrica) e avvolgere le eccezioni generate in un tipo di eccezione Runtime (uno di cui sopra, a seconda di quale si sceglie).

Tuttavia, in realtà dipende che cosa avete bisogno. Ad un certo punto si sarà ancora bisogno di eccezioni maniglia o la vostra applicazione sarà lanciare un'eccezione in fase di esecuzione e applicazione non farà quello che ci si aspettava se li dont gestire.

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

Ricorda è ancora necessario per gestire l'eccezione. Ciò non significa che questo è gonna lavoro tutto bene.

Le eccezioni devono essere catturati da qualche parte. Se ho capito bene si dispone di una classe che è avvolto intorno a questa fabbrica, dire una FactoryWrapper. Da qualche parte nel codice si utilizza tale classe wrapper e siete in grado di buttare sia un'eccezione o prenderlo perché il metodo in cui si sta utilizzando probabilmente è circondato a un certo punto (in una classe base probabilmente) da un blocco try / catch, mentre il prima di altri (per il quale si sta passando il vostro riferimento FactoryWrapper) è probabilmente l'ultima risorsa (non è una pratica buona, ma potrebbe essere un metodo che non viene mai chiamato) in cui la necessità eccezione a essere catturato.

Questa è solo una possibile spiegazione sul motivo per cui non si può generare l'eccezione nella vostra classe. Come altri hanno già detto, cerca di non utilizzando la riflessione, perché è molto più lento che le altre alternative.

Si potrebbe utilizzare una fabbrica astratta e poi una fabbrica per ogni tipo. Vedere i dettagli qui e qui . Spero che questo aiuti.

Modifica

qui è un interessante articolo su di riflessione. Essa vi darà un'idea quando usarlo.

Mi raccomando che si lavora su prendere confidenza con la scrittura di gestori di eccezioni. In caso contrario, l'unica opzione è quella di enigma il codice con dichiarazioni throws che diventa difficoltà fastidiosi e le cause, come avete visto già.

In questo caso, il corpo del metodo può lanciare due eccezioni controllate:. ClassNotFoundException dalla chiamata forname() e InstantiationException dalla chiamata newInstance()

Come meglio gestire queste dipende dalla vostra applicazione e la vostra preferenza. Come suggerito da un'altra risposta, una possibilità è quella di prendere semplicemente e generare eccezioni non controllati. Questo è ragionevole se si prevede che queste eccezioni non dovrebbe mai verificarsi una volta che l'applicazione è completa. Questo è probabilmente l'approccio Vorrei prendere qui, dal momento che se uno di questi si è verificato eccezioni sarebbe probabilmente indicare un errore di configurazione.

Ma se c'è motivo di pensare queste eccezioni potrebbero ragionevole verificarsi durante il normale uso, si dovrebbe pensare a come si desidera gestire loro. Ad esempio, se il nome del pezzo sottoclasse venivano stipulato una GUI da un utente (non probabile, lo so, ma solo per fare il punto) poi un ClassNotFoundException diventa molto più probabile dal momento che il nome potrebbe facilmente essere scritto male. In tale situazione, potrebbe avere senso per consentire questo metodo per lanciare questa eccezione, e richiedono al chiamante di cattura e gestire (ad esempio fornendo un back messaggio all'utente che la classe richiesta non esiste).

Utilizzando riflessione come si fa non è l'ideale. Non appena si rinomina una classe Piece e clienti passano Hardcoded pienamente qualificati-classnames, la vostra applicazione si romperà. Il suggerimento di Elite Gent evita questo problema, ma richiede ancora clienti di conoscere la classe concreta, che è esattamente ciò che il modello cerca di fabbrica da nascondere. Un approccio migliore a mio parere sarebbe quello di usare sia un enum per rappresentare tipi pezzo e far passare client che come argomento per il metodo di fabbrica, o creare metodi di fabbrica separati per ogni tipo (con 6 tipi pezzo che è possibile).

Dato che io sono procrastinare in ogni caso, qui un esempio di enum-approccio:

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

Ho fatto tutto quello statico qui per mantenere l'esempio autosufficiente. Normalmente Campo, pezzo, AbstractPiece e Rook sarebbe classi del modello di livello superiore e PieceFactory sarebbe di livello superiore anche.

Questo è un modo migliore per andare per il tuo esempio penso, ed evita l'emissione gestione delle eccezioni.

Tornando a ciò, ci sono un paio di approcci si può considerare (in base al vostro approccio riflessione):

Lanciare Throwable come hai fatto è una cattiva pratica in quanto accomuna tutti gli errori e rende la gestione degli errori molto ingombrante e poco trasparente per i clienti. Non farlo a meno che non ci sono altre opzioni.

Declare 'getta' sul metodo per tutte le eccezioni controllate. Per decidere se questo è valido, in considerazione se il cliente deve conoscere e capire il tipo di eccezione si sta gettando. Nel tuo esempio, se il cliente che vuole creare un Rook conoscere e comprendere l'InstantiationException, IllegalAccessException e ClassNotFoundException gettato dal codice di riflessione? Probabilmente non in questo caso.

metterli in un'eccezione di runtime che non ha bisogno di essere catturato dai clienti. Questo non è sempre una buona idea. Il fatto che il codice che si sta chiamando è lanciare eccezioni controllate di solito ha una ragione. Nel tuo esempio che stavi facendo la riflessione, e questo può andare male in molti modi (l'API dichiara LinkageError, ExceptionInInitializerError, ClassNotFoundException, IllegalAccessException, InstantiationException e SecurityException). Avvolgendo le eccezioni controllate in un'eccezione di runtime non fa che problema andare via. Considero questa operazione un 'codice di odore'. Se l'errore si intende un guasto del sistema irrecuperabile, allora potrebbe essere una scelta valida, ma nella maggior parte dei casi si vorrebbe gestire tali fallimenti più garbo.

un'eccezione verificata personalizzato per un sottosistema completo. Si veda ad esempio, org.springframework.dao.DataAccessException di primavera che viene utilizzato per avvolgere tutte le eccezioni di accesso ai dati implementazione specifici. Questo significa che i clienti dovranno prendere un solo tipo di eccezione e possono capire i dettagli se hanno bisogno di. Nel tuo caso si potrebbe creare una controllato PieceCreationException e l'uso che per avvolgere tutti gli errori di riflessione. Si tratta di una valida gestione pattern eccezioni, ma penso che potrebbe essere un po 'a mano pesante per il vostro PieceFactory.

nullo

Return. Si poteva cogliere tutte le eccezioni all'interno del codice e semplicemente restituire null se si verificano. Basta assicurarsi che il JavaDoc indica chiaramente questo. Un inconveniente di questo approccio è che i clienti potrebbero dover verificare la presenza di valori nulli in tutto il mondo.

Return uno specifico tipo di errore. Si tratta di un geek (molto orientato agli oggetti) approccio che ho visto nel nucleo API Java in un posto un po 'indietro (accidenti, non ricordo dove). Per questo è necessario creare un tipo di pezzo in più:

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

e restituire un'istanza di questo tipo, quando si verifica un errore durante la creazione. Il vantaggio è che è più auto-documentazione di restituire un semplice null-valore, ma i clienti avrebbero naturalmente dovuto controllare questo usando qualcosa come instanceof. Se non lo fanno, poi si incontreranno l'UnsupportedOperationException generata quando i metodi pezzi sono chiamati. Un po 'pesante, ma molto esplicito. Non sono sicuro che vorrei andare così lontano, ma è ancoraun'idea interessante.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top