Wrapping Primitives per abilitare la restituzione null - Cattiva pratica?

1

Spesso sono tentato di racchiudere interi, ecc. esclusivamente allo scopo di scrivere metodi che possono restituire null . Negativo 1 può funzionare in molti casi, ma troppo spesso (specialmente nel suono) è un valore di ritorno valido.

Spesso, per aggirare questo problema, restituisco un riferimento a un oggetto più grande che contiene la primitiva in questione e chiama un getter. Questo sembra meno efficiente del wrapper, e in alcuni casi meno incapsulante.

Quindi, ci sono delle penalità con il wrapping per questo motivo? Qualcuno lo fa? Questo odore?

    
posta anthropomo 05.01.2013 - 19:25
fonte

1 risposta

5

Una tecnica che uso a volte in C / C ++ consiste nel fare in modo che la funzione restituisca un valore booleano che indica se la funzione è stata in grado di calcolare il risultato e quindi passare un puntatore come argomento di funzione a dove la funzione può memorizzare il risultato . Se la funzione restituisce true, puoi prendere il valore che vuoi usando il puntatore. Per le lingue che non dispongono di puntatori, ad esempio Java, è possibile passare un oggetto contenitore mutevole (di solito un array) per ottenere un effetto simile. Questo non è molto comune in Java, anche se ricordo di averlo visto una o due volte prima. Questo approccio ha il vantaggio che non è necessario eseguire il wrapping delle primitive, ma è necessario creare l'array in linguaggi come Java.

Scala e Guasa di Guava di Google per Java offre implementazioni di Option pattern per fare questo genere di cose in un modo diverso. Invece di restituire null quando la funzione non può restituire un valore, si restituisce un'istanza di Option che non ha alcun valore, quindi il chiamante utilizza i metodi dell'oggetto Option restituito per determinare se il valore di ritorno effettivo è stato calcolato dalla funzione o meno e anche ottenere il valore se è valido. Poiché le classi Option sono generiche, devi comunque avvolgere le tue primitive, quindi questo approccio aumenta effettivamente il sovraccarico necessario per gestire il valore restituito. Tuttavia, le opzioni rendono il codice più facile da capire rispetto alla verifica di un valore di ritorno intero per null. Inoltre, rende evidente dalla firma della funzione che la funzione potrebbe non restituire sempre un valore valido.

Ecco un esempio forzato del precedente approccio in Java:

boolean divide(int[] out, int a, int b) {
    if (b == 0) return false;
    out[0] = a/b;
    return true;
}

int x = ...;
int y = ...;
int[] out = new int[1];
if (divide(out, x, y)) {
    int d = out[0];
    // do something with d
} else {
    // deal with division by zero
}

e quest'ultimo con le classi di Guava:

Optional<Integer> divide(int a, int b) {
    if (b == 0) return Optional.absent();
    return Optional.of(a/b);
}

int x = ...;
int y = ...;
Optional<Integer> o = divide(x, y);
if (o.isPresent()) {
    int d = o.get();
    // do something with d
} else {
    // deal with division by zero
}

Dovresti anche chiederti se dovresti lanciare un'eccezione invece di farlo. Ad esempio, in precedenza, sarebbe probabilmente meglio fare sempre la divisione e gestire l'ArithmeticException, o controllare se y è zero prima di chiamare la funzione. La decisione giusta dipende da una serie di fattori, ad esempio se il sovraccarico della gestione delle eccezioni sarà un problema per il tuo caso d'uso.

    
risposta data 05.01.2013 - 20:33
fonte

Leggi altre domande sui tag