I principi SOLID in Java

immagine di fantasia

I principi SOLID rappresentano un insieme di cinque principi fondamentali della programmazione orientata agli oggetti (OOP) che mirano a rendere il software più manutenibile, estendibile e comprensibile. Seguendo questi principi, gli sviluppatori Java possono scrivere codice più robusto e flessibile, riducendo al minimo la probabilità di introdurre bug durante le modifiche future. Questo articolo esplorerà ciascuno dei principi SOLID in dettaglio, fornendo esempi pratici in Java.

Cosa sono i principi SOLID?

L’acronimo SOLID sta per:

  • Single Responsibility Principle (Principio di Responsabilità Singola)
  • Open/Closed Principle (Principio Aperto/Chiuso)
  • Liskov Substitution Principle (Principio di Sostituzione di Liskov)
  • Interface Segregation Principle (Principio di Segregazione delle Interfacce)
  • Dependency Inversion Principle (Principio di Inversione delle Dipendenze)

1. Single Responsibility Principle (SRP) – Principio di Responsabilità Singola

  • Definizione: Una classe dovrebbe avere una e una sola ragione per cambiare. In altre parole, una classe dovrebbe avere una sola responsabilità.
  • Spiegazione: Questo principio mira a evitare classi “God Class” che gestiscono troppe responsabilità. Quando una classe ha troppe responsabilità, diventa difficile da capire, testare e manutenere. Qualsiasi modifica a una delle responsabilità può potenzialmente influenzare le altre.
  • Esempio:
// Esempio di classe con molte responsabilità (violazione dell'SRP)
class Libro {
    public String titolo;
    public String autore;

    public void salvaSuDatabase() { /* ... */ }
    public void stampaDettagli() { /* ... */ }
}

// Esempio di classi con singola responsabilità (rispetto dell'SRP)
class Libro {
    public String titolo;
    public String autore;
}

class LibroRepository {
    public void salva(Libro libro) { /* ... */ }
}

class LibroPrinter {
    public void stampa(Libro libro) { /* ... */ }
}

Nell’esempio corretto, le responsabilità di salvare su database e stampare i dettagli sono state separate in classi distinte, LibroRepository e LibroPrinter, rispettando l’SRP.

2. Open/Closed Principle (OCP) – Principio Aperto/Chiuso

  • Definizione: Le entità software (classi, moduli, funzioni, ecc.) dovrebbero essere aperte all’estensione, ma chiuse alla modificazione.
  • Spiegazione: Questo significa che dovremmo essere in grado di aggiungere nuove funzionalità senza modificare il codice esistente. Questo si ottiene spesso attraverso l’uso di astrazioni come interfacce e classi astratte.
  • Esempio:
// Violazione dell'OCP
class CalcolatriceArea {
    public double calcolaArea(Object forma) {
        if (forma instanceof Rettangolo) {
            Rettangolo rettangolo = (Rettangolo) forma;
            return rettangolo.base * rettangolo.altezza;
        } else if (forma instanceof Cerchio) {
            Cerchio cerchio = (Cerchio) forma;
            return Math.PI * cerchio.raggio * cerchio.raggio;
        }
        // ... altre forme
        return 0; // o eccezione
    }
}

// Rispetto dell'OCP
interface Forma {
    double calcolaArea();
}

class Rettangolo implements Forma {
    double base;
    double altezza;
    // ...
    @Override
    public double calcolaArea() { return base * altezza; }
}

class Cerchio implements Forma {
    double raggio;
    // ...
    @Override
    public double calcolaArea() { return Math.PI * raggio * raggio; }
}

class CalcolatriceArea {
    public double calcolaArea(Forma forma) {
        return forma.calcolaArea();
    }
}

Nell’esempio corretto, l’aggiunta di una nuova forma non richiede la modifica della classe CalcolatriceArea.

3. Liskov Substitution Principle (LSP) – Principio di Sostituzione di Liskov

  • Definizione: I sottotipi devono essere sostituibili con i loro tipi base senza alterare la correttezza del programma.
  • Spiegazione: In altre parole, se una classe B eredita da una classe A, allora possiamo usare un oggetto di tipo B ovunque sia richiesto un oggetto di tipo A, senza che il programma si comporti in modo inatteso.
  • Esempio: Un classico esempio di violazione è il quadrato che eredita dal rettangolo. Un quadrato ha base e altezza uguali, quindi non si adatta perfettamente al concetto di rettangolo dove base e altezza possono essere diverse.

4. Interface Segregation Principle (ISP) – Principio di Segregazione delle Interfacce

  • Definizione: Un client non dovrebbe essere forzato a dipendere da metodi che non usa.
  • Spiegazione: È meglio avere molte interfacce specifiche che poche interfacce generiche. Questo previene che le classi implementino metodi non necessari.
  • Esempio:
// Violazione dell'ISP
interface Macchina {
    void guida();
    void vola(); // Non tutte le macchine volano
}

// Rispetto dell'ISP
interface MacchinaTerrestre {
    void guida();
}

interface MacchinaVolante {
    void vola();
}

5. Dependency Inversion Principle (DIP) – Principio di Inversione delle Dipendenze

  • Definizione:
    • I moduli di alto livello non dovrebbero dipendere da moduli di basso livello. Entrambi dovrebbero dipendere da astrazioni.
    • Le astrazioni non dovrebbero dipendere dai dettagli. I dettagli dovrebbero dipendere dalle astrazioni.
  • Spiegazione: Questo principio promuove l’uso di interfacce o classi astratte per disaccoppiare i moduli.
  • Esempio:
// Violazione del DIP
class Motore {
    public void avvia() { /* ... */ }
}

class Auto {
    private Motore motore;
    public Auto() {
        this.motore = new Motore();
    }
    // ...
}

// Rispetto del DIP
interface Motore {
    void avvia();
}

class MotoreDiesel implements Motore {
    public void avvia() { /* ... */ }
}

class Auto {
    private Motore motore;
    public Auto(Motore motore) {
        this.motore = motore;
    }
    // ...
}

In conclusione, i principi SOLID forniscono una solida base per la progettazione di software orientato agli oggetti in Java. Seguendo queste linee guida, si può ottenere un codice più manutenibile, estendibile e testabile, migliorando la qualità complessiva del software.

Lezioni sul linguaggio Java

Pubblicato da Carlo Contardi

Carlo Contardi, docente di informatica e sviluppatore Full Stack, condivide la sua passione per la programmazione e l’informatica attraverso il suo blog Space Coding. Offre preziosi consigli e soluzioni pratiche a chi vuole imparare a programmare o migliorare le proprie abilità. 🚀👨‍💻

Translate »