• remove if-else
  • code optimization
  • clean code
  • interface-oriented programming
  • conditional logic

3 potenti tecniche di codifica per eliminare condizionali disordinati

Introduzione a tre potenzi tecniche di codifica per ottimizzare e semplificare strutture condizionali complesse, migliorando la qualità e la manutenibilità del codice.

Yijun
Yijun
Developer

Nel sviluppo software, spesso ci troviamo di fronte a logiche di codice che devono gestire più scenari. Se non gestite correttamente, queste logiche possono facilmente evolversi in lunghe catene di if-else o enormi strutture switch. Questo articolo introdurrà diverse tecniche efficaci per ottimizzare queste strutture, migliorando la qualità e la manutenibilità del codice.

1. Programmazione difensiva: ritorno anticipato

Supponiamo di sviluppare un sistema di autenticazione utente che deve verificare vari stati dell'utente prima di consentire l'accesso:

Questo codice ha evidenti problemi strutturali. Utilizza strutture if-else profondamente annidate, rendendo il codice difficile da leggere e manutenere. Man mano che il numero di controlli sulle condizioni aumenta, aumenta anche il livello di indentazione del codice, formando un cosiddetto codice "a forma di freccia". La logica di gestione degli errori è sparsa in diversi livelli di annidamento, il che non favorisce una gestione unitaria. Più importante, la logica principale del codice - il caso in cui l'accesso è consentito - è sepolta in profondità all'interno di più strati di giudizi condizionali, mancando di intuitività. Questo stile di codifica non solo riduce la leggibilità del codice, ma aumenta anche il rischio di errori e rende difficile l'espansione del codice.

Possiamo ottimizzare questo codice utilizzando l'approccio del "ritorno anticipato":

Adottando la strategia del "ritorno anticipato", abbiamo ottimizzato con successo la struttura originale del codice.

Questo metodo porta diversi miglioramenti:

  • Riduce significativamente la complessità dell'annidamento del codice. Ogni controllo della condizione è gestito in modo indipendente, rendendo la logica complessiva più chiara e comprensibile. Questa struttura appiattita migliora non solo la leggibilità del codice, ma riduce anche notevolmente la difficoltà di manutenzione.
  • Questo metodo di ottimizzazione raggiunge una gestione centralizzata della logica di gestione degli errori. Restituendo i risultati immediatamente dopo ogni controllo delle condizioni, evitiamo l'esecuzione di codice non necessaria centralizzando la gestione di vari scenari di errore, rendendo l'intero processo di gestione degli errori più organizzato.
  • La logica principale del codice - le condizioni per consentire l'accesso - diventa più prominente. Questa struttura rende immediatamente evidente lo scopo principale del codice, migliorando notevolmente l'espressività e la comprensibilità del codice.

2. Metodo della tabella di ricerca

Spesso ci imbattiamo in scenari in cui è necessario restituire risultati diversi in base a input diversi. Se non gestite adeguatamente, queste logiche possono facilmente evolversi in lunghe catene di if-else o enormi strutture switch. Ad esempio, in una piattaforma di e-commerce, è necessario restituire le descrizioni dello stato corrispondenti in base a diversi stati dell'ordine:

Questo è uno scenario tipico di restituzione di risultati diversi in base a diversi casi. Man mano che il numero di casi aumenta, la dichiarazione switch o i giudizi if-else diventano lunghi. Inoltre, in questo scenario, se gli utenti devono tradurre questi contenuti di stato in altre lingue, sarebbe necessario modificare il corpo della funzione o aggiungere nuove funzioni, il che comporterebbe costi di manutenzione significativi.

In questo caso, possiamo utilizzare il metodo della tabella di ricerca per ottimizzare il codice:

Prima di tutto, utilizzando un oggetto Map per memorizzare la relazione di mapping tra stati e descrizioni, il codice diventa più conciso. Abbiamo anche reso facile spostare le descrizioni dello stato nei file di configurazione, fornendo comodità per l'internazionalizzazione e gli aggiornamenti dinamici. Quando vengono aggiunti nuovi stati, non è necessario modificare il codice logico principale; basta aggiungere le coppie chiave-valore corrispondenti nella configurazione.

3. Programmazione orientata alle interfacce

Quando si sviluppano grandi sistemi software, spesso è necessario supportare più fornitori di servizi o moduli funzionali. Possiamo considerare l'uso della programmazione orientata alle interfacce nella fase di progettazione del software per facilitare le espansioni successive, eliminando così la complessità di molteplici giudizi condizionali portata dalla programmazione "hard-coded" nei sistemi complessi.

Supponiamo di sviluppare un sistema di traduzione multilingue che deve supportare diversi fornitori di servizi di traduzione. Se non si considera la programmazione orientata alle interfacce dalla fase di progettazione, le espansioni successive diventeranno molto difficili:

Questa implementazione utilizza una struttura semplice e grezza di if-else per selezionare i fornitori di traduzione, rendendo il codice difficile da mantenere e espandere. Quando si aggiungono nuovi fornitori di traduzione in futuro, il codice esistente deve essere modificato e, man mano che è necessario supportare più fornitori di traduzione, il codice diventerà sovraccarico e difficile da mantenere. Allo stesso tempo, questo metodo complesso è anche difficile da testare con unità perché non è facile simulare diversi fornitori di traduzione.

Per risolvere questi problemi, possiamo utilizzare la programmazione orientata alle interfacce per ottimizzare il codice. La programmazione orientata alle interfacce è un modo importante per implementare il polimorfismo, consentendo a diversi oggetti di rispondere diversamente allo stesso messaggio.

Processo di implementazione:

  1. Definire l'interfaccia della strategia di traduzione:
  1. Implementare questa interfaccia per ciascun fornitore di traduzione:
  1. Rifattorizzare la classe TranslationService, passando la strategia come parametro:
  1. Utilizzare il codice ottimizzato:

Definendo l'interfaccia TranslationStrategy e introducendo la programmazione orientata alle interfacce, abbiamo ottenuto i seguenti vantaggi:

  • TranslationService può utilizzare strategie di traduzione diverse per ciascuna chiamata.
  • Aggiungere nuovi fornitori di traduzione diventa semplice, basta creare una nuova classe strategica e implementare l'interfaccia.
  • Il codice client può selezionare la strategia da utilizzare per ciascuna traduzione senza modificare la logica centrale di TranslationService.
  • Ogni strategia di traduzione può essere testata indipendentemente, migliorando la testabilità del codice.
  • Evitando il mantenimento dello stato in TranslationService, il servizio diventa più privo di stato e thread-safe.

Conclusione

Ottimizzare le strutture delle istruzioni condizionali è un mezzo importante per migliorare la qualità del codice. I tre metodi introdotti in questo articolo - programmazione difensiva, metodo della tabella di ricerca e programmazione orientata alle interfacce (combinata con il polimorfismo) - hanno ciascuno i loro scenari applicabili:

  1. La programmazione difensiva è adatta per gestire controlli di condizioni multipli e indipendenti e può ridurre efficacemente l'annidamento del codice.
  2. Il metodo della tabella di ricerca è adatto per gestire esigenze che reagiscono diversamente a casi diversi, rendendo il codice più conciso e più facile da mantenere.
  3. La programmazione orientata alle interfacce combinata con il polimorfismo è adatta per costruire sistemi complessi ma flessibili, migliorando la flessibilità e la scalabilità del codice.

Nello sviluppo reale, spesso dobbiamo scegliere i metodi appropriati in base a situazioni specifiche e talvolta è necessario applicare in modo completo più tecniche. L'importante è bilanciare la semplicità, la leggibilità e la manutenibilità del codice, scegliendo la soluzione che meglio si adatta al problema attuale.

Ricorda, l'ottimizzazione eccessiva può portare a codice eccessivamente complesso. Mantenere il codice semplice e leggibile è sempre il principio primario. Quando applichi queste tecniche, dovrebbero essere fatte scelte sagge basate sulle esigenze specifiche del progetto e sul livello tecnico del team.