![]() |
I principi SOLID sono un insieme di linee guida fondamentali per la progettazione di software robusto, scalabile e manutenibile. Questi principi, introdotti da Robert C. Martin (conosciuto come "Uncle Bob"), sono particolarmente utili nella programmazione orientata agli oggetti (OOP). L'applicazione corretta di questi principi aiuta a ridurre la complessità del codice, migliorare la riusabilità e facilitare la manutenzione del software nel tempo:
![]() |
In questo articolo, esploreremo in dettaglio ciascun principio, illustrando prima un esempio di codice errato e poi la sua corretta applicazione in JavaScript.
1. Single Responsibility Principle (SRP) - Principio di Responsabilità Unica
Il principio di responsabilità unica afferma che una classe dovrebbe avere una sola ragione per cambiare, ovvero dovrebbe essere responsabile di un solo aspetto del software. In altre parole, una classe dovrebbe avere un solo scopo ben definito.
Se una classe assume più responsabilità, diventa più difficile da testare, manutenere e modificare. Questo porta a un codice rigido e fragile, in cui una modifica a una parte della classe può inaspettatamente influenzarne altre. Separare le responsabilità consente di ridurre il rischio di bug e migliorare la chiarezza e l'organizzazione del codice.
Codice errato (violazione di SRP)
Problema: La classe User ha più responsabilità: gestisce sia i dati dell'utente che la persistenza e l'invio di email. Se cambiamo la logica di salvataggio o di invio email, dovremo modificare questa classe, violando SRP.
Codice corretto (applicazione di SRP)
Soluzione: Abbiamo separato le responsabilità tra tre classi: User, UserRepository e EmailService. Ora possiamo modificare il metodo di persistenza o l'invio di email senza alterare la logica dell'utente.
2. Open/Closed Principle (OCP) - Principio Aperto/Chiuso
Il principio aperto/chiuso afferma che un'entità software (classe, modulo, funzione, ecc.) dovrebbe essere aperta all'estensione ma chiusa alla modifica. Questo significa che dovremmo poter aggiungere nuove funzionalità senza dover modificare il codice esistente, evitando così di introdurre nuovi bug in codice già testato e funzionante.
Questo principio è particolarmente utile quando il software cresce nel tempo e dobbiamo aggiungere nuove funzionalità senza rischiare di rompere quelle esistenti. Il modo migliore per rispettare OCP è usare l'ereditarietà o il polimorfismo per estendere il comportamento delle classi senza modificarle direttamente.
Codice errato (violazione di OCP)
Problema: Se vogliamo aggiungere un nuovo tipo di sconto, dobbiamo modificare la classe Discount, violando OCP.
Codice corretto (applicazione di OCP)
Soluzione: Ora possiamo aggiungere nuovi tipi di sconto senza modificare Discount, rispettando OCP.
3. Liskov Substitution Principle (LSP) - Principio di Sostituzione di Liskov
Il principio di sostituzione di Liskov afferma che le classi derivate dovrebbero poter sostituire le loro classi base senza alterare il comportamento del programma. Se una sottoclasse viola questo principio, significa che non è realmente un sostituto valido della classe padre e potrebbe causare malfunzionamenti nel codice.
Una violazione tipica di LSP avviene quando una sottoclasse modifica o rimuove il comportamento ereditato, causando errori nelle parti del codice che si aspettano il comportamento originale.
Codice errato (violazione di LSP)
Problema: Square cambia il comportamento di Rectangle in modo non previsto. Se una funzione si aspetta un Rectangle, potrebbe comportarsi in modo errato con uno Square.
Codice corretto (applicazione di LSP)
Soluzione: Separiamo Rectangle e Square, facendo in modo che entrambe derivino da un'astrazione comune (Shape) senza violare LSP.
4. Interface Segregation Principle (ISP) - Principio di Segregazione delle Interfacce
Il principio di segregazione delle interfacce afferma che nessun client dovrebbe essere costretto a dipendere da metodi che non utilizza. In altre parole, è meglio avere più interfacce specifiche piuttosto che un'unica interfaccia generale con metodi non pertinenti per tutte le classi che la implementano.
Questo principio aiuta a evitare la creazione di interfacce troppo grandi e complesse, migliorando la manutenibilità e la chiarezza del codice. Se una classe è costretta a implementare metodi non rilevanti, può indicare che l'interfaccia è mal progettata.
Codice errato (violazione di ISP)
Problema: La classe Worker ha un unico metodo eat() che è pertinente solo per i lavoratori umani, ma non per i robot. Costringere Robot ad implementare un metodo che non ha senso per la sua logica è una violazione di ISP.
Codice corretto (applicazione di ISP)
Soluzione: Abbiamo separato le responsabilità in due interfacce distinte (Workable e Eatable). Ora, la classe Robot implementa solo Workable, senza essere costretta a implementare metodi inutili come eat(). D'altra parte, la classe Human può implementare entrambe le interfacce, beneficiando della separazione delle responsabilità.
5. Dependency Inversion Principle (DIP) - Principio di Inversione delle Dipendenze
Il principio di inversione delle dipendenze afferma che le classi ad alto livello non dovrebbero dipendere direttamente dalle classi a basso livello, ma entrambe dovrebbero dipendere da astrazioni (interfacce o classi astratte). Inoltre, le astrazioni non dovrebbero dipendere dai dettagli concreti, ma il contrario.
Seguire questo principio permette di ridurre il forte accoppiamento tra le classi, rendendo il codice più flessibile e testabile. Se una classe dipende direttamente da un'implementazione concreta, ogni modifica a quella implementazione potrebbe richiedere modifiche anche alla classe dipendente.
Codice errato (violazione di DIP)
Problema: UserService dipende direttamente dalla classe concreta MySQLDatabase. Se volessimo cambiare database, dovremmo modificare UserService, violando DIP.
Codice corretto (applicazione di DIP)
Soluzione: UserService ora dipende da un'astrazione (Database) e non da un'implementazione concreta. Questo consente di sostituire MySQLDatabase con un'altra implementazione (es. PostgreSQLDatabase) senza modificare UserService.
Conclusione
I principi SOLID sono fondamentali per scrivere codice pulito, flessibile e manutenibile. Applicarli correttamente aiuta a ridurre l'accoppiamento tra le classi, migliorare la testabilità e rendere il software più adattabile ai cambiamenti.
Seguire questi principi consente agli sviluppatori di evitare molte delle problematiche comuni nella programmazione orientata agli oggetti, migliorando la qualità del codice e la sua longevità.
Se vuoi migliorare ulteriormente la tua comprensione di SOLID, prova a refattorizzare il codice esistente applicando questi principi e osserva come migliora la leggibilità e la modularità del tuo software.
Follow me #techelopment
Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
telegram: @techelopment_channel
whatsapp: Techelopment
youtube: @techelopment

