Zasada podstawienia Liskov

"Dochodzenie do mistrzostwa wymaga dwóch elementów: wiedzy i pracy." - Robert C. Martin

Zasada podstawienia Liskov

Liskov

Zasada podstawienia Liskov mówi nam, że w miejscu klasy bazowej można użyć dowolnej klasy pochodnej, a więc zgodność interfejsu oraz wszystkich metod musi być zachowana. Zasada ta jest zgodna z zasadą otwarte/zamknięte, gdyż klasa pochodna nie ma wpływu na zachowanie klasy nadrzędnej. Oznacza to, że klasy pochodne muszą być substytucyjne w stosunku do klas bazowych. Do złamania tej zasady następuje najczęściej w trzech przypadkach: kiedy mechanizm dziedziczenia został źle rozplanowany i interfejs polimorficzny jest zbyt ogólny; kiedy zastosowano dziedziczenie bez mechanizmu polimorfizmu; kiedy klasy pochodne nadpisują metody klasy bazowej , zastępując jej niedopracowaną logikę. W mechanizmie dziedziczenia nie powinno dojść do sytuacji, kiedy klasy pochodne nadpisują metody klasy bazowej – powinny je ewentualnie rozszerzać. Poniższy program łamie zasadę podstawienia Liskov, ze względu na fakt, że klasa Basenji nie może zastąpić bazowej klasy Dog. Klasa Dog wymuszą implementację metody bark(), w przypadku której nielogiczne jest jej zastosowanie dla klasy Basenji, gdyż jest to jedyna rasa psów, która nie szczeka.

class Dog
{
public function bark()
{
echo 'Woow woow!
;
}

public function move()
{
echo 'Biegnę! 
;
}
}

class GermanShepherd extends Dog
{
}

class Basenji extends Dog
{
}

$dog = new Basensji();
$dog -> bark();
$dog -> move();

Dobrym rozwiązaniem jest zastosowanie dodatkowych klas, które podzielą rasy psów na rasy szczekające i nieszczekające. Klasa BarkingDogs  oraz klasa NonBarkingDogs dziedziczy po klasie Dog metodę move(). Metoda bark() jest przypisana tylko do klasy BarkingDogs. Owczarek niemiecki szczeka, dlatego klasa GermanShepherd dziedziczy po klasie BarkingDogs, a klasa Basenji po klasie NonBarkingDogs. Poprawne zastosowanie reguły podstawienia Liskov zostało przedstawione poniżej:

class Dog
{
public function move()
{
echo 'Biegnę! 
;
}
}

class BarkingDogs extends Dog
{
public function bark()
{
echo 'Woow woow!
;
}
}

class NonBarkingDogs extends Dog
{
}

class GermanShepherd extends BarkingDogs
{
}

class Basenji extends NonBarkingDogs
{
}

$dog = new Basensji();
$dog -> bark();
$dog -> move();