Le eccezioni di una sottoclasse dovrebbero estendere le eccezioni della superclasse o il mio spazio dei nomi?

6

La nostra libreria estende un'altra libreria (di terze parti). Quando creiamo una classe child nella nostra libreria e vogliamo generare eccezioni, queste eccezioni dovrebbero estendere le eccezioni dalla classe genitore o dal nostro spazio dei nomi? Ad esempio:

class Their_Exception extends Exception {}

class Their_Class {}
class Their_Class_Exception extends Their_Exception {}

class Our_Exception extends Exception {}

class Our_Class extends Their_Class {}
class Our_Class_Exception extends Our_Exception {} // or Their_Class_Exception?

È meglio mantenere il nostro codice come sopra e ampliare il nostro spazio dei nomi? Per come la vedo io, abbiamo queste alternative:

  1. Estendi il nostro spazio dei nomi, recuperando tutti i possibili casi di Their_Class_Exception e gettando Our_Class_Exceptions al loro posto (incapsulamento completo, ma in generale potrebbe essere una buona quantità di rilavorazione)
  2. Estendi il nostro spazio dei nomi, ma non prendi solo Their_Class_Exception in Our_Class (probabilmente significa più blocchi catch)
  3. Estendi Their_Class_Exception (sembra contro-intuitivo, potrebbe introdurre bug rilevando le eccezioni sbagliate)

Quale di questi è l'approccio migliore in generale, al fine di mantenere il nostro codice coerente?

    
posta cmbuckley 02.12.2011 - 18:32
fonte

2 risposte

5

Se c'è qualche possibilità di sostituire questa API con un'altra ad un certo punto in futuro, vai con l'opzione 1, prendi e avvolgi la loro eccezione nel tuo.

Generalmente, meno ci si riferisce alle API di terze parti nel proprio codice, meglio è, a meno che il codice non sia intrinsecamente legato all'API (ad esempio la JVM o .NET Framework).

Se non è così, o se è troppo lavoro, chiediti: Our_Class_Exception è in realtà un'estensione di Their_Class_Exception? cioè è un'altra forma della stessa eccezione.

Se è così, estendilo (opzione 3), perché finirai con le doppie catture ovunque, se non lo fai. Ma se questo è il caso, perché non usare la loro eccezione?

In caso contrario o se non sei ancora sicuro, gioca in sicurezza ed estendi il tuo spazio dei nomi (opzione 2).

    
risposta data 02.12.2011 - 19:14
fonte
1

Il principio di sostituzione di Liskov richiede che i metodi di override nelle classi derivate generino solo le eccezioni generate dal metodo della classe base.

class Base {
    void f() throws AnException { ... ; }
}

class Derived extends Base {
    void f() throws AnException /* ok */, 
                    AnotherException /* LSP violation, not allowed in Java */ {
        ...;
    }
}

class Victim {
    void g(Base b) {
        try {
             b.f();
        }
        catch (AnException e) { ... }
    }
}

Derived d = new Derived();
Victim v = new Victim();
v.g(d); // oops, AnotherException unexpectedly thrown

Questo è ok:

class AnotherException extends AnException { ... }
class Derived extends Base {
    void f() throws AnException {
        ...
        throw new AnotherException();
    }
}
    
risposta data 03.12.2011 - 08:13
fonte

Leggi altre domande sui tag