È buona norma implementare due metodi predefiniti di Java 8 in termini reciproci?

14

Sto progettando un'interfaccia con due metodi correlati, in questo modo:

public interface ThingComputer {
    default Thing computeFirstThing() {
        return computeAllThings().get(0);
    }

    default List<Thing> computeAllThings() {
        return ImmutableList.of(computeFirstThing());
    }
}

Circa la metà delle implementazioni calcolerà solo una cosa, mentre l'altra metà potrebbe calcolare di più.

Questo ha precedenti nel codice Java 8 ampiamente usato? So che Haskell fa cose simili in alcune tipologie ( Eq per esempio).

Il lato positivo è che devo scrivere molto meno codice rispetto a se avessi due classi astratte ( SingleThingComputer e MultipleThingComputer ).

Lo svantaggio è che un'implementazione vuota viene compilata ma esplosa in fase di esecuzione con un StackOverflowError . È possibile rilevare la ricorsione reciproca con un ThreadLocal e dare un errore migliore, ma aggiunge un sovraccarico al codice non buggato.

    
posta Tavian Barnes 18.06.2015 - 21:12
fonte

1 risposta

16

TL; DR: non farlo.

Quello che mostri qui è un codice fragile.

Un'interfaccia è un contratto. Dice "indipendentemente dall'oggetto che ottieni, può fare X e Y." Come è scritto, la tua interfaccia non X né Y perché è garantita per causare uno stack overflow.

Lanciare un errore o sottoclasse indica un errore grave che dovrebbe non essere catturato:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

Inoltre, VirtualMachineError , la classe genitore di StackOverflowError , dice questo:

Thrown to indicate that the Java Virtual Machine is broken or has run out of resources necessary for it to continue operating.

Il tuo programma non dovrebbe preoccuparsi delle risorse JVM . Questo è il lavoro della JVM. Fare un programma che causa un errore JVM come parte del normale funzionamento è sbagliato. O garantisce che il tuo programma si bloccherà o costringerà gli utenti di questa interfaccia a intercettare errori di cui non dovrebbe preoccuparsi.

Potresti conoscere Eric Lippert da tali sforzi come emerito "membro del comitato di progettazione linguistica C #". Parla di caratteristiche linguistiche che spingono le persone verso il successo o l'insuccesso: mentre questa non è una caratteristica linguistica o parte della progettazione linguistica, il suo punto è altrettanto valido quando si tratta di implementare interfacce o utilizzare oggetti.

You remember in The Princess Bride when Westley wakes up and finds himself locked in The Pit Of Despair with a hoarse albino and the sinister six-fingered man, Count Rugen? The principle idea of a pit of despair is twofold. First, that it is a pit, and therefore easy to fall into but difficult work to climb out of. And second, that it induces despair. Hence the name.

Fonte: C ++ e Pit Of Despair

Avere un'interfaccia lancia un StackOverflowError di default spinge gli sviluppatori nel Pit of Despair ed è cattiva idea . Invece, spingere gli sviluppatori verso la Fossa del successo . Rendilo facile per usare la tua interfaccia correttamente e senza arrestare la JVM.

La delega tra i metodi va bene qui. Tuttavia, la dipendenza dovrebbe andare in un modo. Mi piace pensare alla delega dei metodi come un grafico diretto . Ogni metodo è un nodo sul grafico. Ogni volta che un metodo chiama un altro metodo, traccia un bordo dal metodo chiamante al metodo chiamato.

Se si disegna un grafico e si nota che è ciclico, si tratta di un odore di codice. Questo è un potenziale per spingere gli sviluppatori nel Pit of Despair. Si noti che non dovrebbe essere categoricamente vietato, solo che si deve usare cautela . Gli algoritmi ricorsivi specificatamente avranno cicli nel grafico delle chiamate: va bene. Documentalo e avvisa gli sviluppatori. Se non è ricorsivo, prova a interrompere quel ciclo. Se non puoi, scopri quali input potrebbero causare un overflow dello stack e li mitigano o li documentano come un ultimo caso, se non funziona altrimenti.

    
risposta data 19.06.2015 - 01:27
fonte

Leggi altre domande sui tag