Se un Closeable lancia un'eccezione se usato dopo essere stato chiuso, anche se non è necessario?

4

Supponiamo di avere questa interfaccia:

public interface OutputChannel extends Closeable {
    public void writeOutput(String output);
}

Poi ci sono diverse classi che implementano questa interfaccia e generalmente è possibile che writeOutput() non possa essere utilizzato dopo che sono stati chiusi.

Tuttavia, tra di loro ci sono classi come NullOutputChannel (che non fa mai nulla, quindi non gli interessa se è stato chiuso), o classi che delegano l'output ad altri Closeable s (quindi non donano t attenzione - non fanno IO stessi)

Non sono sicuro che ogni OutputChannel debba sempre generare IllegalStateException se writeOutput() è stato chiamato dopo close() , o se deve tollerarlo silenziosamente a meno che non incontri un problema di I / O effettivo.

Finora sono venute fuori alcune visioni in conflitto:

LANCIO :

  • Chiamare writeOutput() dopo close() è un errore e non dovrebbe essere tollerato. Anche se non importa in caso di NullOutputChannel ecc., Potrebbe importare se NullOutputChannel è stato sostituito da un'altra implementazione di OutputChannel .
  • L'interfaccia si comporterà in modo più coerente se il lancio dell'eccezione viene deciso dalla logica generale che non è possibile scrivere dopo la chiusura, piuttosto che dai dettagli di implementazione di una particolare classe.
  • Se una classe non lancia un'eccezione in questo caso, nasconde solo un bug. Sarebbe meglio se l'errore si manifestasse indipendentemente dall'implementazione scelta.

Ignora :

  • Se una particolare classe non ha problemi con qualcosa, non dovrebbe generare eccezioni.
  • Controllare lo stato di closed in una classe a cui non importa comunque è una complicazione inutile.

Sarei grato per alcuni argomenti per entrambi gli approcci o per alcune buone pratiche consigliate in queste situazioni.

    
posta Cinnam 18.09.2015 - 23:03
fonte

2 risposte

4

Hai già affermato i pro ei contro in modo abbastanza chiaro nella domanda; l'unica vera domanda a cui rispondere è, quale argomento è più convincente?

La mia linea di ragionamento sull'argomento sarebbe di tenere a mente un paio di punti: uno dei principi fondamentali dell'OOP è la possibilità di essere reperibili. Stai creando un'interfaccia e una manciata di singole classi che dovrai scrivere una sola volta, ma potrebbero essere utilizzate centinaia di volte.

Un altro principio importante è la sostituzione di Liskov, che dice che tutto ciò che eredita da una base deve essere in grado di sostituire il tipo di base in tutti i comportamenti osservati. (Può fare anche altre cose, ma se non fa l'insieme principale di comportamenti, stai violando la sostituzione di Liskov.)

Quindi, se hai un sacco di codice disparato che usa la tua interfaccia Closeable -descended, e si aspetta di avere qualcosa che si comporta come un Closeable , allora deve comportarsi come un Closeable in tutti i modi, compresa l'applicazione degli invarianti previsti. Uno dei punti di Interfacce e sostituzione di Liskov è che lo stesso codice potrebbe utilizzare discendenti diversi di un tipo di base dichiarato in momenti diversi e si desidera che funzioni sempre lo stesso.

Inoltre, su una traccia simile, ricorda il principio Fail Fast. Se si ha un errore nel codice, si desidera rilevarlo il più rapidamente possibile. Ciò significa che se stai utilizzando un NullOutputChannel all'inizio e non utilizzi un OutputChannel funzionale fino a molto più tardi, non vuoi aspettare fino a "molto più tardi" prima di scoprire che il tuo codice utilizza% l'interfaccia diOutputChannel è glitchy.

    
risposta data 18.09.2015 - 23:25
fonte
2

L'approccio "ignora" in realtà non ha motivo di stare in piedi.

"Se una particolare classe non ha problemi con qualcosa, non dovrebbe generare eccezioni": no, una classe dovrebbe, tra le altre cose, onorare un'interfaccia, quindi dovrebbe avere un grosso problema con tutto ciò che viola le regole stabilite dall'interfaccia. È irrilevante se la violazione dell'interfaccia abbia qualcosa a che fare con il funzionamento interno della classe che implementa l'interfaccia.

"Controllare lo stato chiuso in una classe a cui non importa comunque è una complicazione inutile": no, non è una complicazione inutile, è una parte assolutamente indispensabile per assicurarsi che l'interfaccia sia utilizzata correttamente.

La facilità di programmazione non dovrebbe essere considerata uguale alla facilità di fare errori non rilevati . (Questo è qualcosa che Edsger W. Dijkstra ha detto, la fonte è qui .)

In generale, l'abitudine di assicurarsi sempre che tutto stia accadendo esattamente come previsto e che nulla sia lasciato al caso, porta a sistemi più stabili, più prevedibili, meno bacati, meno caotici. Al contrario, scrivere codice che permetta agli errori di passare inosservato è un modo sicuro per tenersi sempre occupati a correggere i bug dappertutto.

    
risposta data 19.09.2015 - 12:42
fonte

Leggi altre domande sui tag