SOLID cosa sono i 5 principi della programmazione a oggetti

Solid figure geometriche solide
Formazione
1

S.O.L.I.D. è un acronimo, riferito ai cinque principi di progettazione orientata agli oggetti (OOD o OOP). Sono delle linee guida che gli sviluppatori possono utilizzare per creare software in modo semplice da gestire, mantenere ed estendere. La comprensione di questi concetti ti renderà uno sviluppatore migliore e ti consentirà di evitare problemi nella gestione del software. Cosa significa essere un buon programmatore?

Chiunque abbia un po’ di esperienza nella programmazione software, giudica codice software scritto da altri, utilizzando parametri di giudizio basati sul proprio percorso di crescita professionale.

Nel corso della mia carriera professionale, ho conosciuto molti sviluppatori, e ho visto migliaia di righe di codice e quando ho bisogno di valutare l’abilità di uno sviluppatore guardo principalmente due fattori:

  • Semplicità nella lettura del codice;
  • Quanto è probabile che il loro codice funzioni ed evolverà nel tempo.

Fortunatamente, ci sono alcuni fondamenti o principi che rendono facile essere migliori nella codifica.

l’acronimo S.O.L.I.D. sta per:
S: principio di responsabilità unica
O: principio aperto-chiuso
L: Principio di sostituzione di Liskov
I: Principio di segregazione dell’interfaccia
D: Principio di inversione delle dipendenze

Iniziamo con approfondire il primo principio SOLID, cioè il

Single Responsibility Principle

Una classe (o modulo) dovrebbe avere un solo motivo per cambiare, per evolversi.

Il concetto di per se è molto semplice, però per raggiungere questa semplicità il percorso di attuazione può essere molto complicato. Una classe dovrebbe avere un solo motivo per cambiare.

Ma perché? 

Perché è così importante avere una sola ragione per cambiare?

Ad esempio se ci sono due diversi motivi per cambiare, è concepibile che due diversi team possano lavorare sullo stesso codice per due diversi motivi. Ciascuno dovrà implementare la propria soluzione, che nel caso di un linguaggio compilato (come C ++, C # o Java), potrebbe portare a moduli incompatibili con altri team o altre parti dell’applicazione.

Altro esempio, se si usa un linguaggio interpretato, si potrebbe dover ripetere il test della stessa classe o modulo per motivi diversi. Questo implica più lavoro, tempo e impegno per il controllo qualità.

Andare a identificare l’unica feature che una classe o un modulo dovrebbe avere è molto più complesso che guardare semplicemente una checklist per eseguire i test. 

Ma proviamo a ragionare da un punto di vista meno tecnico, e cioè proviamo ad analizzare l’utenza della nostra classe o modulo, cioè chi andrà ad utilizzarla. Un aspetto fondamentale che dobbiamo sempre tenere in considerazione, è il fatto che gli utenti dell’applicazione o del sistema che sviluppiamo che sono serviti da un particolare modulo saranno quelli che richiedono modifiche allo stesso. Quelli serviti chiederanno il cambiare la classe o il modulo. 

Alcuni esempi di moduli e relativa utenza:

  • Modulo manutenzione: l’utenza è composta da amministratori di database e architetti software.
  • Modulo di reporting: l’utenza è composta da impiegati, contabili e produzione.
  • Modulo di calcolo dei pagamenti per un sistema di gestione buste paga: l’utenza può includere avvocati, manager e contabili.
  • Modulo di ricerca testi per un sistema di gestione delle biblioteche: l’utenza può essere rappresentata dal bibliotecario oppure dai visitatori e clienti della biblioteca stessa.

Quindi se il primo passo consiste nel ricercare gli attori o l’attore che ha il ruolo di interlocutore con il modulo, associare persone fisiche a tutti i ruoli può essere difficile. In una piccola azienda una sola persona può svolgere più ruoli mentre in una grande azienda possono esserci più persone che hanno un unico ruolo. 

Sembra più ragionevole identificare i ruoli, invece che le persone o gli utenti.

Quindi:

  • l’utenza del sistema software definisce le ragioni del cambiamento;
  • una responsabilità è una famiglia di funzioni che soddisfa le esigenze di un particolare attore, cioè dell’utenza del sistema;
  • gli attori, l’utenza diventa una fonte di cambiamento per la famiglia di funzionalità che deve soddisfare l’esigenza dell’utente stesso;
  • l’evoluzione delle esigenze dell’utenza, guida l’evoluzione delle funzionalità;

SOLID principi

Vediamo degli esempi

Supponiamo di avere una classe Libro che incapsula il concetto di un libro e le sue funzionalità.

class Libro {

    function getTitolo() {

        return “Un Grande Libro”;

    }

    function getAutore() {

        return “Alessandro Baricco”;

    }

    function prossimaPagina() {

        // pagina successiva

    }

    function printPaginaCorrente() {

        echo “contenuto della pagina corrente”;

    }

}

Questa è una normalissima classe. Abbiamo un libro, e la classe ci può fornire il titolo, ci può fornire l’autore e può voltare pagina. Infine, è anche in grado di stampare la pagina corrente sullo schermo. 

C’è però un piccolo problema. 

Ragionando sugli attori coinvolti nella gestione dell’oggetto Libro, chi potrebbero essere? 

Possiamo facilmente pensare a due attori diversi qui: Gestione del libro (come il bibliotecario) e Meccanismo di presentazione dei dati (come il modo in cui vogliamo fornire il contenuto all’utente: su schermo, interfaccia utente grafica, interfaccia utente di solo testo, forse stampa) . 

Abbiamo quindi due attori molto diversi che interagiscono con la classe.

In poche parole questa classe fa un mix tra:

  • la logica aziendale con 
  • la presentazione 

questo può essere un problema perché viola il principio di responsabilità unica (SRP). 

Come possiamo modificare, come possiamo migliorare questo codice per rispettare il principio di responsabilità unica ?

Dai un’occhiata al codice seguente:

class Libro {

    function getTitolo() {

        return “Oceano Mare”;

    }

    function getAutore() {

        return “Alessandro Baricco”;

    }

    function turnPagina() {

        // pagina successiva

    }

    function getPaginaCorrente() {

        echo “contenuto della pagina corrente”;

    }

}

interface Printer {

    function printPage($page);

}

class StampaLibro implements Printer {

    function stampaPagine($page) {

        echo $page;

    }

}

 

class HtmlPrinter implements Printer {

    function stampaPagine($page) {

        echo ‘<div style=”single-page”>’ . $page . ‘</div>’;

    }

}

Questo esempio molto semplice mostra come separare la presentazione dalla logica aziendale, e nel rispetto dell’SRP offre grandi vantaggi nella flessibilità del nostro progetto.

Vediamo un altro esempio:

Un esempio simile a quello sopra è quando un oggetto può salvare e recuperare se stesso dalla presentazione.

class Libro {

    function getTitolo() {

        return “Oceano Mare”;

    }

    function getAutore() {

        return “Alessandro Baricco”;

    }

    function turnPagina() {

        // pagina successiva

    }

    function getPaginaCorrente() {

        return “contenuto della pagina corrente”;

    }

    function salva() {

        $nomefile = ‘/documenti/’. $this->getTitolo(). ‘ – ‘ . $this->getAutore();

        file_put_contents($nomefile, serialize($this));

    }

}

Come prima, anche qui possiamo identificare diversi attori come Gestione del libro (come il bibliotecario) e la Persistenza. Ogni volta che vogliamo cambiare il modo in cui passiamo da una pagina all’altra, dobbiamo modificare questa classe. Possiamo avere diversi motivi di cambiamento.

class Libro {

    function getTitolo() {

        return “Oceano Mare”;

    }

    function getAutore() {

        return “Alessandro Baricco”;

    }

    function turnPagina() {

        // pagina successiva

    }

    function getPaginaCorrente() {

        return “contenuto della pagina corrente”;

    }

}

class SimpleFilePersistence {

    function salva(Libro $libro) {

        $nomefile = ‘/documenti/’ . $libro->getTitolo() . ‘ – ‘ . $book->getAutore();

        file_put_contents($nomefile, serialize($book));

    }

}

Spostare l’operazione di persistenza in un’altra classe separerà chiaramente le responsabilità e saremo liberi di scambiare metodi di persistenza senza influire sulla nostra classe Libro. Ad esempio, l’implementazione di una classe DatabasePersistence sarebbe banale e la nostra logica aziendale costruita attorno alle operazioni con i libri non cambierà.

Continua leggendo il secondo principio Open/Closed —>

1 commento

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

marketing google trends
Formazione
Come usare Google Trends per fare marketing in tempo reale

Una delle maggiori difficoltà incontrate nel 2020 dalle aziende è stato capire in quali settori merceologici diversificare il proprio business: infatti gran parte dei settori industriali ha subìto pesanti contraccolpi rendendo quasi impossibile alle aziende la loro penetrazione, soprattutto in qualità di nuovo player.   Pochissimi i settori del manifatturiero …

business intelligence strategia
Metodi
Strategie per la Business Intelligence di successo

La costruzione di una strategia di successo per la vostra Business Intelligence, parte da una corretta visione degli obiettivi.   Vediamo qui di seguito alcuni punti fondamentali.   Valutare la situazione attuale Sarebbe un grave errore sottovalutare questo aspetto. Valutare la situazione attuale vuol dire analizzare i processi, le strutture …

open closed principle
Metodi
Open / Closed, secondo principio S.O.L.I.D.

Le entità software (classi, moduli, funzioni, ecc.) Dovrebbero essere aperte per l’estensione, ma chiuse per la modifica. Progettare il software: moduli, classi e funzioni in modo tale che quando è necessaria una nuova funzionalità, non dovremmo modificare il codice esistente ma piuttosto scrivere nuovo codice che verrà utilizzato dal codice …