Il Principio
La “I” di S.O.L.I.D. sta per Interface Segregation Principle (da ora ISP), o Principio di Segregazione delle Interfacce. Abbastanza corto, presenta il seguente enunciato:
“No client should be forced to depend on methods it does not use.”
Possiamo tradurlo così:
“Nessun client dovrebbe essere forzato a dipendere da metodi che non usa.”
Il principio è stato proposto da “Zio Bob” Robert C. Martin, durante una sua consulenza alla Xerox. L’azienda aveva sviluppato un sistema per la gestione di stampe e fax, tuttavia troppo lento per gli standard richiesti.
Zio Bob ha risolto brillantemente la situazione, appunto, formulando (ed applicando) quello che poi è diventato l’ISP.
La Spiegazione
Se hai letto le sezioni dedicate agli altri principi S.O.L.I.D. avrai sicuramente notato che, ogni tanto, ho suggerito di applicare una certa soluzione tramite le interfacce. Le necessità di astrazione sono pane quotidiano ed è vitale scrivere un software che sappia astrarre al punto giusto i suoi componenti per poter essere scalabile quanto serve e quando serve.
Come ben sai, un’interfaccia è una sorta di “contratto” che definisce alcune funzionalità tramite dichiarazioni di metodi. Nel rispettare questo contratto, le classi devono necessariamente implementare tali metodi.
Nella prima “lezione” hai scoperto il Single Responsibility Principle, che “esorta” una classe a svolgere una ed una sola operazione. In modo simile, applicare l’ISP significa dividere un’interfaccia “grande” in tante piccole interfacce, in modo tale da non doversi portare dietro tanti metodi quando non servono.
Nel gergo tecnico, queste piccole interfacce ottenute vengono chiamate “Role Interface”, proprio perchè definiscono dei “ruoli” da assegnare alle classi.
Vediamo un tipico esempio di ISP violato e come porvi rimedio.
L’Esempio
Supponiamo di avere a che fare con un sistema che gestisce dei mezzi di trasporto. In una prima iterazione ci occuperemo esclusivamente di automobili. Avremo svariate classi per ogni tipologia di auto, ma di partenza implementeremo innanzitutto un’interfaccia.
Ottimo, abbiamo la partnership! Dobbiamo estendere il supporto della nostra applicazione alle macchine d’epoca e alle astronavi!
Non ci stai credendo: astronavi? Beh, nella programmazione a volte succede anche questo.
La prima cosa che fai è quindi andare a modificare l’interfaccia.
interface VeichleInterface {
public function turnOn();
public function turnOff();
public function accelerate();
public function brake();
public function lightsOn();
public function lightsOff();
public function radioOn();
public function radioOff();
public function switchToUsbMusic();
public function switchToRadioMusic();
// metodi aggiunti per il volo…
public function takeOff();
public function land();
public function sensorsCheck();
}
Abbiamo modificato l’interfaccia per aggiungere le funzionalità del volo. A questo punto, dove necessario, aggiungeremo queste nuove funzionalità…
In caso contrario? Le Tesla sono stupende, ma non volano ancora! Figuriamoci le macchine d’epoca…
Beh, potresti sempre scrivere dei metodi che ritornano “null” o qualcosa del genere…
BLEAH. Fermo! Scherzo ovviamente, non fare mai una cosa del genere.
La verità è che dovremmo ragionare in modo totalmente diverso. L’ISP viene in nostro soccorso e ci dice chiaramente quello che dobbiamo fare: dividere questa mega interfaccia in tante più piccole. La divisione dovrebbe avvenire per funzionalità (ruoli, ricordi?), permettendo alle classi interessate di dover implementare solo quelle desiderate.
Dall’interfaccia vista prima, quindi, arriveremmo a…