Programmazione ifless (fondamentalmente senza condizionali)

Ho avuto un collega che mi ha detto che una volta lavorava per una società che aveva come politica di non avere mai condizionali (“se” e “switch” dichiarazioni) nel codice e che lasciavano che tutte le decisioni nel codice fossero fatte usando polimorfismo e (suppongo) altri principi OO.

Capisco il ragionamento alla base di questo, di avere un codice che è più ASCIUTTO e più facile da aggiornare, ma sto cercando una spiegazione più approfondita di questo concetto. O forse fa parte di un approccio progettuale più generale.

Se qualcuno ha delle risorse per questo o sarebbe disposto a spiegare o anche avere qualche altro termine relativo a questo posso usare per trovare più risposte sarei molto grato.

Ho trovato una domanda su SO che era un po ‘imparentata ma non ho familiarità con il C ++ quindi non capisco troppo delle risposte lì.

(Non sono un guru OO btw ma posso gestirlo)

    Sono più abile in PHP, e dopo di ciò Python preferirei le informazioni che usano quelle lingue.

    Aggiornamento: chiederò al mio collega maggiori informazioni su cosa intendesse esattamente.

    Aggiornamento 2015: dopo alcuni anni di esperienza nella programmazione vedo ora che l’objective di questa politica era probabilmente quello di impedire ai programmatori di aggiungere funzionalità in modo casuale aggiungendo semplicemente condizionali (se le istruzioni) in determinati punti. Un modo migliore per estendere il software consiste nell’utilizzare il “principio aperto / chiuso” in cui il software viene esteso utilizzando l’ereditarietà e il polimorfismo. Dubito fortemente che la politica sia stata super rigorosa su tutti i condizionali, dato che è piuttosto difficile andare completamente senza di loro.

    Ci sono alcune risorse sul sito della campagna Anti-IF , come questo articolo .

    Credo che sia una questione di laurea. I condizionali non sono sempre cattivi, ma possono essere (e frequentemente sono) abusati.

    Ulteriori pensieri (un giorno dopo)

    Refactoring: migliorare il design del codice esistente è un buon riferimento a questo argomento (e molti altri). Copre Sostituisci condizionale con polimorfismo . Ce n’è anche uno nuovo, Sostituisci condizionale con visitatore , sul sito web.

    Apprezzo la semplicità e la responsabilità individuale rispetto alla rimozione di tutte le dichiarazioni if . Questi tre obiettivi spesso coincidono. Gli strumenti di analisi statica che supportano la metrica della complessità ciclomatica possono indicare rapidamente il codice con condizionali nidificati o seriali. Le dichiarazioni if possono rimanere post-refactoring, ma potrebbero essere scomposte in metodi più piccoli e / o classi multiple.

    Aggiornamento: Michael Feathers ha scritto un articolo su Programmazione incondizionata .

    Questo è un argomento molto popolare: Phil Haack on Death to the IF statement !

    Dopo alcuni anni di programmazione torno alla mia domanda, il cui contesto ora capisco un po ‘meglio.

    C’è una bella chiacchierata di Sandi Metz in cui lei rifiuta una palla di dichiarazioni if-if davvero pelose a qualcosa di sempre meno peloso: https://www.youtube.com/watch?v=8bZh5LMaSmE

    Ho letto il post che hai linkato e sembra che stessero parlando principalmente della rimozione della necessità di condizionali all’interno di una class , da non confondere con tutto il codice in generale. L’idea è che se hai bisogno di controllare lo stato di un object (usando un condizionale) per determinare se ha certe funzionalità, allora in realtà hai due oggetti (uno che supporta la funzionalità e uno che non lo fa) e dovresti definirli come due classi correlate invece.

    Ho avuto un collega che mi ha detto che una volta lavorava per una società che aveva come politica di non avere mai condizionali (“se” e “switch” dichiarazioni) nel codice e che lasciavano che tutte le decisioni nel codice fossero fatte usando polimorfismo e (suppongo) altri principi OO.

    Penso che il tuo collega abbia frainteso qualcosa o usato le parole sbagliate per spiegarlo. E non puoi completamente evitare dichiarazioni condizionali.

    C’è una cosa da dire: proliferare di se le affermazioni all’interno di OOP possono essere un sintomo di una ctriggers programmazione. Qualche esempio:

    Non utilizzare se per controllare il valore di ritorno della funzione come una vecchia programmazione in stile C:

     int ret = some_func(); if (ret != null) //do something 

    Questo era tipico nel codice C ma con OOP dovresti usare l’eccezione:

     try{ do_something(); }catch(Exception e){ e.printStackTrace(); //why I was not able to do something handle(e); //there is something else I could do to handle the occurred error } 

    A volte, se la proliferazione delle affermazioni è correlata a una ctriggers progettazione. Considera l’esempio seguente in Java:

     BaseClass base; if (base instanceof DerivedClassOneFromBase){ DerivedClassOneFromBase d = (DerivedClassOneFromBase)base; d.methodOne(); }else if (base instanceof DerivedClassOneFromBase){ DerivedClassTwoFromBase d = (DerivedClassTwoFromBase)base; d.methodTwo(); } 

    Questo è un altro esempio di affermazioni bad if, probabilmente correlate a un design errato. Se i due oggetti derivati ​​avessero un metodo comune definito nella loro class base BaseClass, avresti potuto chiamare quel metodo invece di controllarne il tipo concreto e lanciarli:

     base.commonMethod(); 

    A volte i condizionali all’interno dei metodi sono cattivi in ​​quanto sono un segno che stai eseguendo più funzioni o più tipi di metodi in un unico metodo.

    Se hai una class chiamata Automobile e sottoclassi come Auto e Bici, e un metodo come:

     drive(Automobile a) if (a.isCar) // do stuff else if (a.isBike) // do stuff 

    sei più gentile a fare qualcosa di sbagliato. Anche se non è un interruttore basato sul tipo, spesso può essere sbagliato. Se il metodo sta eseguendo più funzioni a seconda di alcune variabili, spesso cerca di fare più di una cosa e probabilmente dovrebbe essere separato in più metodi.

    Per esempio:

     save(Car c) if (c is new) // do some stuff else if (c is old) // do some stuff 

    potrebbe potenzialmente essere suddiviso in salvataggio e aggiornamento, in quanto sono due funzioni diverse. Anche se dipende.

    Completamente vietando se le dichiarazioni sarebbero sciocco anche se hanno molti casi d’uso validi.

    Evitare i condizionali non significa necessariamente che devi eseguire il polimorfismo o l’ereditarietà, ad esempio:

    Hai 3 diverse cartelle per archiviare immagini caricate, video caricati e pdf caricato

    Puoi scrivere codice come:

     uploadMedia(mediaType){ if(mediaType == images){ uploadTo("myProject/images"); }else if(mediaType == videos){ upoloadTo("myProject/videos); }else if(mediaType == pdf){ uploadTo("myProject/pdf"); } } 

    Un’altra alternativa che le persone potrebbero utilizzare è la commutazione:

     uploadMedia(mediaType){ switch(mediaType){ case : images uploadTo("myProject/images"); break; case : videos uploadTo("myProject/videos"); break; case : pdf uploadTo("myProject/pdf"); break; } } 

    Ma allora puoi evitare totalmente le dichiarazioni condizionali usando qualcosa come dizionario / hashmap / json (a seconda di qualsiasi cosa tu lavori con):

    Per esempio :

     HashMap mediaMap = new HashMap<>(); mediaMap.put("images","myProject/images"); mediaMap.put("videos","myProject/videos"); mediaMap.put("pdf","myProject/pdf"); //mediaType can be images/videos/pdf same as keys of mediaMap uploadMedia(mediaType){ uploadTo(mediaMap.get(mediaType)); } 

    Questa è una sorta di pseudo-codice, quindi potrebbero esserci errori di syntax, ma nel complesso questo concetto è utile anche per evitare condizionali. Anche la linea di codice può essere ridotta.