Tutorial

Principio della Sostituzione di Liskov, terzo principio S.O.L.I.D.

Le classi figlie non dovrebbero mai influire o modificare le definizioni del tipo della classe genitore.

Il concetto di questo principio è stato introdotto da Barbara Liskov in un keynote della conferenza del 1987 e successivamente pubblicato in un articolo insieme a Jannette Wing nel 1994. La loro definizione originale è la seguente:

Sia q (x) una proprietà dimostrabile su oggetti x di tipo T. Allora q (y) dovrebbe essere dimostrabile per oggetti y di tipo S dove S è un sottotipo di T.

Successivamente, con la pubblicazione dei principi SOLID di Robert C.Martin nel suo libro Agile Software Development, Principles, Patterns, and Practices e poi ripubblicata nella versione C # del libro Agile Principles, Patterns, and Practices in C #, la definizione divenne noto come principio di sostituzione di Liskov.

Questo ci porta alla definizione data da Robert C. Martin: I sottotipi devono essere sostituibili con i loro tipi di base.

Più semplicemente, una sottoclasse dovrebbe sovrascrivere i metodi della classe genitore in un modo che non interrompe la funzionalità dal punto di vista di un cliente. Ecco un semplice esempio per dimostrare il concetto.

class Vehicle {

    function startEngine() {

        // Default engine start functionality

    }

 

    function accelerate() {

        // Default acceleration functionality

    }

}

Data una classe Veicolo – può essere astratta – e due implementazioni:

class Car extends Vehicle {

    function startEngine() {

        $this->engageIgnition();

        parent::startEngine();

    }

 

    private function engageIgnition() {

        // Ignition procedure

    }

}

 

class ElectricBus extends Vehicle {

    function accelerate() {

        $this->increaseVoltage();

        $this->connectIndividualEngines();

    }

 

    private function increaseVoltage() {

        // Electric logic

    }

 

    private function connectIndividualEngines() {

        // Connection logic

    }

}

class Driver {

    function go(Vehicle $v) {

        $v->startEngine();

        $v->accelerate();

    }

}

Una classe client dovrebbe essere in grado di utilizzare entrambi, se può utilizzare Vehicle.

Il che ci porta a una semplice implementazione del Template Method Design Pattern come l’abbiamo utilizzato nel OCP.

Potrebbe interessarti anche il secondo principio SOLID: https://bloginnovazione.it/open-closed-secondo-principio-s-o-l-i-d/3906/

Sulla base della nostra precedente esperienza con il principio Open / Closed, possiamo concludere che il principio di sostituzione di Liskov è in stretta relazione con l’OCP. Infatti, “una violazione di LSP è una violazione latente di OCP” (Robert C. Martin), e il Template Method Design Pattern è un classico esempio di rispetto e implementazione di LSP, che a sua volta è una delle soluzioni per rispettare anche OCP .

Esempio di violazione LSP

class Rectangle {

    private $topLeft;

    private $width;

    private $height;

 

    public function setHeight($height) {

        $this->height = $height;

    }

 

Newsletter sull’Innovazione
Non perderti le notizie più importanti sull'Innovazione. Iscriviti per riceverle via e-mail.

    public function getHeight() {

        return $this->height;

    }

 

    public function setWidth($width) {

        $this->width = $width;

    }

 

    public function getWidth() {

        return $this->width;

    }

}

Iniziamo con una forma geometrica di base, un rettangolo. È solo un semplice oggetto dati con setter e getter per larghezza e altezza. Immagina che la nostra applicazione funzioni e sia già distribuita su diversi client. Ora hanno bisogno di una nuova funzionalità. Devono essere in grado di manipolare i quadrati.

Nella vita reale, in geometria, un quadrato è una particolare forma di rettangolo. Quindi potremmo provare a implementare una classe Square che estende una classe Rectangle. Si dice spesso che una classe figlia è una classe genitore, e anche questa espressione è conforme a LSP, almeno a prima vista.

class Square extends Rectangle {

    public function setHeight($value) {

        $this->width = $value;

        $this->height = $value;

    }

 

    public function setWidth($value) {

        $this->width = $value;

        $this->height = $value;

    }

}

Un quadrato è un rettangolo con larghezza e altezza uguali e potremmo eseguire una strana implementazione come nell’esempio precedente. Potremmo sovrascrivere entrambi i setter per impostare sia l’altezza che la larghezza. Ma in che modo ciò influirà sul codice client?

class Client {

    function areaVerifier(Rectangle $r) {

        $r->setWidth(5);

        $r->setHeight(4);

        if($r->area() != 20) {

            throw new Exception(‘Bad area!’);

        }

        return true;

    }

}

È concepibile avere una classe client che verifica l’area del rettangolo e genera un’eccezione se è sbagliato.

function area() {

    return $this->width * $this->height;

}

Ovviamente abbiamo aggiunto il metodo sopra alla nostra classe Rectangle per fornire l’area.

class LspTest extends PHPUnit_Framework_TestCase {

    function testRectangleArea() {

        $r = new Rectangle();

        $c = new Client();

        $this->assertTrue($c->areaVerifier($r));

    }

}

E abbiamo creato un semplice test inviando un oggetto rettangolo vuoto al verificatore di area e il test viene superato. Se la nostra classe Square è definita correttamente, inviarla all’areaVerifier () del Cliente non dovrebbe interrompere la sua funzionalità. Dopo tutto, un quadrato è un rettangolo in tutto il senso matematico. Ma è la nostra classe?

function testSquareArea() {

    $r = new Square();

    $c = new Client();

    $this->assertTrue($c->areaVerifier($r));

}

Quindi, la nostra classe Square non è dopotutto un Rettangolo. Infrange le leggi della geometria. Fallisce e viola il principio di sostituzione di Liskov.

Ercole Palmeri

Newsletter sull’Innovazione
Non perderti le notizie più importanti sull'Innovazione. Iscriviti per riceverle via e-mail.

Articoli recenti

Editori e OpenAI firmano accordi per regolare il flusso di informazioni elaborate dall’Intelligenza Artificiale

Lunedì scorso, il Financial Times ha annunciato un accordo con OpenAI. FT concede in licenza il suo giornalismo di livello…

30 Aprile 2024

I pagamenti online: ecco come i servizi di streaming ti fanno pagare per sempre

Milioni di persone pagano per i servizi di streaming, pagando mensilmente la quota di abbonamento. È opinione comune che tu…

29 Aprile 2024

Veeam presenta il supporto più completo per il ransomware, dalla protezione alla risposta e al ripristino

Coveware by Veeam continuerà a fornire servizi di risposta agli incidenti di cyber-estorsione. Coveware offrirà funzionalità di forensics e remediation…

23 Aprile 2024

Rivoluzione Verde e Digitale: Come la Manutenzione Predittiva sta Trasformando il Settore Oil & Gas

La manutenzione predittiva sta rivoluzionando il settore dell'oil & gas, con un approccio innovativo e proattivo alla gestione degli impianti.…

22 Aprile 2024