La mia implementazione accetta solo URLClassLoader, posso essere meno restrittivo nella firma del mio metodo?

1

Ho scritto un'API Java che accetta ClassLoader s come parametro, anche se non accetterà alcun ClassLoader che non sia un URLClassLoader (perché sono interessato solo al metodo URLClassLoader::getURLs() ) :

/**
 * @throws NullPointerException if classLoader is null.
 * @throws IllegalArgumentException if classLoader is not a URLClassLoader
 */
public void addClassLoader(ClassLoader classLoader) {
  if (!(classLoader instanceof URLClassLoader)) {
    if (classLoader == null) {
      throw new NullPointerException("classLoader must not be null");
    } else {
      throw new IllegalArgumentException("classLoader must be a URLClassLoader");
    }
  }
  this.classLoaders.add((URLClassLoader)classLoader);
}

L'ho fatto per diversi motivi:

  • l'aggiunta di una ClassLoader è una funzionalità piacevole, non imperdibile: la mia API accetta diversi tipi di input;
  • la stragrande maggioranza di ClassLoader s che gli utenti vorranno fornire come parametri sono effettivamente URLClassLoader s (da quelli personalizzati a quelli di app Web);
  • il ClassLoader non è un'API molto conosciuta e URLClassLoader è piuttosto oscuro e gli utenti non dovrebbero imparare le funzionalità di ClassLoader per utilizzare la mia API;
  • il lancio di un ClassLoader in URLClassLoader rende il codice client meno leggibile.

Tuttavia so che probabilmente dovrei far rispettare il fatto che accetterò solo URLClassLoader nel metodo perché ha senso dai dettagli della mia implementazione.

La mia domanda è: dato tutto è OK lasciare la firma del metodo come addClassLoader(ClassLoader) e non addClassLoader(URLClassLoader) ?

    
posta Olivier Grégoire 04.06.2018 - 14:50
fonte

2 risposte

8

No, non è assolutamente OK.

Una firma è una promessa. Stai rompendo quella promessa. Il fatto che la maggior parte delle volte non ci siano ripercussioni è un punto contro tu, non per te: i difetti che causano problemi raramente, imprevedibilmente e in situazioni speciali sono molto peggio di quelli sfacciati. I vistosi difetti causano immediatamente problemi e vengono respinti dalla comunità. Difetti sottili e improbabili possono arrivare fino in produzione e in sistemi critici prima di essere notati.

TL; DR Non fare il possibile per creare difetti impercettibili.

    
risposta data 04.06.2018 - 14:57
fonte
4

Applicherei l'URLClassLoader. Se accetti un ClassLoader e generi un'eccezione.

Il mio primo pensiero è stato che hai ferito il principio di sostituzione di Liskov ma è il contrario: non lo fai t accettare il caso più generale.

Ma è come battere il sistema dei tipi con i piedi. Invece di lasciare che il tuo sistema di tipi controlli il tuo programma mentre lo compili, lo fai su runtime mentre non hai vantaggi.

Ho appena creato alcuni test (vedi sotto) per ottenere il problema. Sembra molto innaturale che il terzo test stia fallendo.

Come utente, mi aspetto che il sistema di tipi debba catturare il terzo caso (fallito) di test. In effetti ho appena iniziato il debugger per indagare.

Questo non dovrebbe essere il caso: L'interfaccia dovrebbe esprimere l'intenzione del metodo e se si osserva il corpo dei metodi, dovrebbe essere lo stesso che si prevede di vedere . Questo non è il caso qui.

@Test
void shouldTakeUrlClassLoader() {
    ClassLoaderExample uut = new ClassLoaderExample();
    uut.addClassLoader(new URLClassLoader(new URL[]{}));
}

@Test
void shouldTakeSubtypeOfUrlClassLoader() {
    ClassLoaderExample uut = new ClassLoaderExample();
    uut.addClassLoader(new SpecializedLoader(new URL[]{}));
}

@Test
void shouldTakeClassLoaderAsArgument() {
    ClassLoaderExample uut = new ClassLoaderExample();
    uut.addClassLoader(new ClassLoaderStub());
}

class ClassLoaderStub extends ClassLoader {}

class SpecializedLoader extends URLClassLoader {
    SpecializedLoader(URL[] urls) {
        super(urls);
    }
}

[EDIT]. Il terzo caso fallisce con java.lang.IllegalArgumentException: classLoader must be a URLClassLoader

    
risposta data 04.06.2018 - 15:18
fonte

Leggi altre domande sui tag