Jeden prosty krok do SOLIDnego kodu - Klasy final w PHP
Słowo kluczowe `final`
Zastosowanie final w klasie, uniemożliwia zastosowanie dziedziczenia względem niej. Także może się wydawać że blokujemy rozszerzalność takiej klasy i zamykamy się na korzyści płynące z mechanizmu polimorfizmu. Ale czy na pewno?
Moim zdaniem `final class` to wspaniałe narzędzie wspierające SOLIDa, chociaż wymaga bardzo dużo samo zaparcia i warto mieć na uwadze że SOLID to tylko zestaw reguł, które można, ale nie trzeba wykorzystywać.
Zobaczmy więc co zyskujemy dzięki stosowaniu słowa `final`.
Liskov Subtition Principle
Zależnie od tego jak spojrzymy na tę regułę zyskujemy w obydwu przypadkach.
W "oryginalnej" regule Liskov, zastosowanie `final` zablokuje możliwości dziedziczenia takiej klasy, a więc całkowicie wyeliminuje potencjalny problem niepoprawnego dziedziczenia klas bazowych, które gdzieś w środku mógłby wpłynąć na poprawność działania aplikacji. Wystarczy przypomnieć sobie przykład z kołem i elipsą.
Natomiast Martin rozszerza tę regułę o koncept Design By Contract
Bertranda Mayer, którą to można sprowadzić do:
"Klasa pochodna nie wymaga więcej i nie dostarcza mniej niż klasa bazowa"
>Jak więc dodać funkcjonalności do klas gdy zablokowaliśmy sobie dziedziczenie?
Bez dziedziczenia jesteśmy zmuszeni do skorzystania z metod wspierających "Kompozycje ponad dziedziczenie". Zwróć uwagę chociażby na wzorzec Dekoratora.
Utworzenie kompozycji klas. Sprowadzi się to do tego, że kontrakt każdej klasy w kompozycji zostanie zachowany, ponieważ kod tych klas nie został zmodyfikowany, ani w pliku klasy, ani poprzez użycie dziedziczenia i być może niepoprawnego nadpisania metody.
Interface Segregation Principle
Nic nie wymusi interfejsów bardziej niż klasa `final`.
Przestają w kodzie istnieć klasy które dziedziczą po czymś, i jeszcze dawały namiastkę tego że ten kod jest rozszerzalny w jakiś sposób. Ponieważ pozbyliśmy się tego mechanizmu. Chcąc nie łamać zasad OCP i DIP, jesteśmy zmuszeni skorzystać z interfejsów.
To pozwoli nawiązać wewnętrzny dialog, który mógłby wyglądać tak. Skoro nie przekaże tu całej klasy (bo złamię DIP), to w sumie jakich metod tej klasy potrzebuję, by stworzyć interfejs specyficzny dla tego typu klienta.
Dependency Inversion Principle
Już miałem okazję wspomnieć o tej zasadzie w tym artykule. Jak to w SOLIDzie bywa, łamiąc jedną zasadę, najprawdopodobniej łamiemy wszystkie inne.
Zgodnie
z DIP powinniśmy wychodzić z założenia że każdy konkret jest ulotny i z
tego powodu powinniśmy stawiać na zależności do abstrakcji. Klasy final wymusiły interfejsy, także zależność od abstrakcji jest na wyciągnięcie ręki.
Open Closed Principle
Chcąc uniknąć powiązania naszego kodu z konkretna implementacją, skorzystamy z technik dynamicznego polimorfizmu, czyli... tak znowu interfejsy.
Single Resposibility Principle
Tutaj chciałbym się dowiedzieć co Ty sądzisz o wpływie `final` na tę regułę. Specjalnie więc "zamilknę" i przejdzę do podsumowania.Czy to sposób na SOLID w projekcie?
Stawiając na klasy final, mam wrażenie że faktycznie dostajemy sporego boosta do SOLIDa w naszym kodzie. Co sądzisz o takim podjeściu? Jestem tez ciekaw co sądzisz o wpływie na SRP.
Jeżeli uznałeś artykuł za ciekawy podziel się z innymi :)
Ten komentarz został usunięty przez administratora bloga.
OdpowiedzUsuń