Personalmente mi piace il primo, scrollata di spalle, che fa semplicemente un semplice ramo su id
all'interno del ciclo. Il polimorfismo è di solito l'alternativa diretta alla ramificazione condizionale con if/switch
, ma può essere o meno ingombrante se gli ID degli elementi sono dinamici e cambiano.
Solo per essere un po 'bizzarro e dato che questa domanda sembra essere indifferente alla lingua, eccoti:
// Applies 'true_func' to elements in the the random-access sequence
// that satisfies 'pred' or 'false_func' otherwise.
applyIf(array, pred, true_func, false_func)
{
for (int i=0; i < array.length; i++) {
if (pred(array[i]))
true_func(array[i]);
else
false_func(array[i]);
}
}
// Returns true if the element has a negative ID.
hasNegativeId(element) {
return element.getId() < 0;
}
E nel chiamante:
applyIf(array, hasNegativeId, doThisStuff, DoOtherStuff);
O semplicemente:
applyIf(array, function(element) {element.getId() < 0;}, doThisStuff, DoOtherStuff);
In realtà non mi piace questa soluzione. Potrei anche odiarlo. Ma mette la tua semplice funzione in due ancora più semplici: un semplice predicato uner sobrio che ritorna vero se un elemento ha un ID negativo e un algoritmo molto generalmente applicabile ( applyIf
) che chiama una funzione o l'altra su ciascuna elemento in una sequenza ad accesso casuale (di cui gli array sono un solo tipo) basato su un predicato.
Ovviamente il cliente deve ancora comporre questa roba insieme, ma le singole funzioni rendono tutto ancora più semplice ora. Puoi renderlo ancora più generalizzato in base a un iteratore / enumerazione diretto anziché a una sequenza di accesso casuale, consentendo a applyIf
di funzionare su qualsiasi struttura dati che sia forwarder iterabile, inclusi elenchi collegati singolarmente, elenchi con collegamento doppio, binari cerca alberi, matrici, hash table, try, quadtrees, lo chiami (purché possa essere iterato in modo sequenziale).
Sta giocando al genere di generosità uber e di riutilizzo del codice in quanto la funzione applyIf
può essere fatta per funzionare praticamente con qualsiasi combinazione di predicati e funzioni da applicare, quindi ha molto, molto più riusabilità di un funzione hardcoded per il controllo degli ID (il tipo di cosa che potrebbe entrare in una libreria standard). Ma non mi piace ancora e preferisco la tua semplice prima soluzione. In questi giorni non mi interessa tanto di queste soluzioni super flessibili. Mi piace quel semplice vecchio ciclo con if
dentro, a meno che tu non debba controllare in modo ridondante gli ID negativi dappertutto (quindi considererei qualcos'altro). Potremmo generalizzare ulteriormente:
// Calls 'true_func' if pred(element) is true,
// 'false_func' otherwise.
iif(pred, true_func, false_func) {
return function(element) {
return pred(element) ? true_func(element): false_func(element);
}
}
// Calls 'func' for each element in the container.
forEach(container, func) {
for (it = container.begin(); it != container.end(); ++it)
func(it.element())
}
A questo punto possiamo fare questo:
forEach(array, iif(hasNegativeId, doThisStuff, doOtherStuff));
Ci sono modi per andare oltre e mettere a punto le cose e generalizzarle ancora di più, ma mi fermo qui. Ancora non mi piace molto questo. Mettiamola in giro per le persone che si divertono a decifrare il loro codice nelle funzioni più giovani e riusabili (qualcosa che mi piaceva, ma non così tanto in questi giorni).
Il motivo principale per cui non mi piace questa soluzione è che la programmazione funzionale perde così tanto della sua eleganza se la usi per causare effetti collaterali. Se doThisStuff
e doOtherStuff
causano effetti collaterali, che presumo che facciano poiché non si utilizza un valore di ritorno, si ottiene solo la difficoltà associata alla programmazione funzionale del flusso di controllo complesso combinato con gli effetti collaterali. La combinazione di questi due può rendere le cose davvero difficili da ragionare. Quindi spesso hai bisogno di un semplice flusso di controllo se vuoi causare effetti collaterali, o nessun effetto collaterale se vuoi un flusso di controllo complesso (non una combinazione dei due). Ecco perché mi piace il tuo ciclo semplice con un'istruzione if
all'interno del migliore. È facile eseguire il debug e seguire in termini di controllo del flusso.