L'importante è mantenere una struttura chiara.
Una semplice istruzione switch / case (o una serie di istruzioni if non annidate) che contiene un ritorno all'interno di ogni caso, sarà perfettamente chiara. Cioè, la mia prima preferenza sarebbe per i ritorni anticipati. Pensa a questi ritorni anticipati come se fossero come una dichiarazione GOTO
.
Ma se si dispone di un nesso di logica leggermente complesso, in cui i ritorni potrebbero dover essere sparsi ovunque a diversi livelli, passerei all'utilizzo di una variabile intermedia e di un approccio a un solo ritorno.
Ai miei occhi, questo approccio sembra sempre un po 'disordinato a prima vista, ma serve a reimpiantare il flusso di controllo strutturato - poiché ora dobbiamo incorporare una logica strutturata che garantisce di arrivare alla fine della funzione senza eseguire nient'altro () le parti che sarebbero state saltate fuori più e più volte, se la funzione fosse tornata in anticipo).
Se hai deciso che i ritorni anticipati non sono buoni, ma diventa anche troppo difficile o irragionevolmente disordinato per implementare l'approccio a rendimento unico, a causa della difficoltà di arrivare alla fine della funzione (senza utilizzare GOTO
s), questo è un segno sicuro che l'intera cosa è strutturata in maniera intrinsecamente scarsa e deve essere ulteriormente suddivisa in metodi separati.
Una volta che abbiamo suddiviso la logica eccessivamente complessa in metodi separati, potremmo essere in grado di tornare tranquillamente a utilizzare i ritorni anticipati in ciascuno di essi.
Se guardi ai ritorni anticipati come questo - che sono simili alle dichiarazioni di GOTO
- vuoi chiederti quanti livelli di (e di quale complessità di) codice strutturato vengono tagliati attraverso il loro uso. Se stai tagliando attraverso un livello (ad esempio uscendo da un ciclo o da un interruttore che è l'istruzione esterna del metodo, con l'ambito interno contenente una o due righe), ciò è accettabile.
Forse è accettabile anche se ci sono un paio di cicli o interruttori annidati, se la logica all'interno della struttura esterna è banale - per esempio, se un ciclo è annidato all'interno dell'altro per attraversare un singolo array bidimensionale, o un interruttore annidato che valuta semplicemente due variabili, prima di raggiungere l'ambito interno contenente una o due istruzioni per ogni caso (o forse solo l'istruzione return).
Ma se stai tagliando la struttura del flusso di controllo che è di diversi livelli in profondità, contenente tutti i tipi di logica non banale a ogni livello, cioè quando il ritorno anticipato può essere visto come il superamento della struttura. Il comportamento del codice non strutturato è molto più difficile da ragionare e verificare, e anche se scritto correttamente, in primo luogo diventa molto difficile da riprendere o modificare in futuro (anche per la persona che lo ha scritto, ma soprattutto per gli altri) .
Come nota finale, se la funzione ha una "coda" di codice comune, come potrebbe essere richiesta per la registrazione, controlli di integrità, o codice di pulizia, o come posizione comoda per impostare un punto di interruzione del debugger - o se si potrebbe voglio che la funzione aggiunga questi in futuro senza codice di rilavorazione radicale che è già testato in uso - quindi i ritorni anticipati sono preclusi in ogni caso, e dovrai usare variabili intermedie e un singolo ritorno come inizio punto. Gli sviluppatori che lavorano in un ambiente in cui questi requisiti sono usuali, possono semplicemente utilizzare le variabili intermedie abitualmente.