Zasada podstawienia 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();