2 lutego 2020

PHP: SOLID [L] Zasada podstawienia Liskov

To trzecia zasada SOLID „Zasada podstawienia Liskov„. Polega na podstawieniu metod klasy dziedziczącej w miejsce klasy bazowej.

Wstęp

Wypada troszkę temat rozwinąć. Klasa dziedzicząca powinna być w 100% zgodna z klasą bazową. Nie powinny mieć miejsca sytuacje, gdy klasa bazowa posiada np. metodę „sell„, a dziedzicząca klasa nie powinna niczego sprzedawać.

Przykład

Przypuśćmy, że nasz program polega na oferowaniu różnej maści raportów. Część z nich można zakupić, natomiast inne są dodawane wyłącznie w gratisie.

Klasa każdego raportu dziedziczy z bazowej o nazwie „Report

Class ReportValuation extends Report
{
   ...
}
Class ReportExpert extends Report
{
   ...
}

Klasa „Report” posiada różne metody z których klasy dziedziczące oczywiście korzystają.

Pojawiła się w klasie bazowej również metoda o nazwie „sell„, ale nasz raport eksperta nie może zostać sprzedany, ponieważ jest dodawany jako bonus do raportu wyceny.

W opisanej powyżej sytuacji, powinniśmy nadpisać raport z klasy bazowej:

Class ReportExpert extends Report
{
   public function sell()
   {
      throw new \Exception('Error');
   }
}

Rozwiązanie przedstawione powyżej to zapewne pierwsza Wasza myśl. Z jednej strony jest to rozwiązanie prawidłowe, bowiem zabezpieczamy program przed sprzedażą raportu który sprzedany zostać nie może. Posiada np. cenę równą „0.00” a to spowoduje błąd przy inicjacji płatności u operatora.

Rozwiązanie problemu

Według trzeciej zasady SOLID, w klasie bazowej nie możemy umieścić metody „sell” bowiem nie wszystkie klasy dziedziczące są w stanie z niej skorzystać. W naszym wypadku skorzystanie z metody „sell” klasy „ReportExpert” zwrócimy wyjątek zamiast inicjacji płatności.

Aby zgodnie z Zasadą Podstawiania Liskov rozwiązać nasz problem, powinniśmy usunąć metodę „sell” z klasy bazowej, a sprzedaż raportów rozwiązać na przykład za pomocą kompozycji.

Zakończenie

Według autora Zasady Podstawiania powinniśmy doprowadzić do sytuacji takiej, że w każdym miejscu wywołania klasy dziedziczącej, powinniśmy móc podstawić klasę bazową.

Klasa dziedzicząca nie powinna zmieniać metod klasy bazowej, a jedynie je rozszerzać.