SOLID 1

Zasada jednej odpowiedzialności

Zasada jednej odpowiedzialności – pierwsza zasada SOLID.

W dzisiejszych czasach jest wiele metod i zasad programowania, którymi kierują się obecni programiści. Nawiązując do myśli Roberta C. Martin’a – “Jedną z różnic pomiędzy bystrymi programistami a profesjonalistami jest to, że profesjonaliści rozumieją, że czytelność jest wszystkim. Profesjonaliści piszą kod zrozumiały dla innych.” stwierdzam, że główną zasadą programowania jest zasada czystego i czytelnego kodu. W programowaniu obiektowym podstawowym założeniem czystego kodu jest wymyślone przez Martin’a, 5 zasad dobrego programowania tzw. SOLID. Pierwszą z pięciu założeń SOLID, jest zasada jednej odpowiedzialności. Mówi ona o tym, że każda klasa powinna odpowiadać za jedną konkretną rzecz oraz, że powinien być tylko jeden powód do modyfikowania klasy. W tym artykule opisze tą metodę oraz przedstawię przykład kodu programu przed użyciem tej zasady i po.

Zastosowanie

Zasada jednej odpowiedzialności z ang. Single responsibility principle jest podstawową zasadą czystego programowaniu obiektowym. Choć jej założenia są bardzo oczywiste, to tak na prawdę stosowanie tej zasady nie jest trywialną umiejętnością. Wymaga od programisty dobrego wyczucia i wysokiego stopnia samodyscypliny. Dzięki tej metodzie zamiast klasy, która będzie odpowiadała za wszystko i będzie miała bardzo dużo linijek kodu, będziemy mieć wiele małych klas, odpowiadających za różne mniejsze części programu np. w klasie Dziennik można stworzyć takie metody jak: wpiszOcene, poprawOcene, jednak funkcja drukujRaportOcen już do tej klasy nie powinna należeć, gdyż według zasady powinniśmy napisać kolejną klasę do generowania raportów.

Innym złym przykładem może być klasa Pliki, która posiada dwie metody: wczytajPlik -odpowiadająca za wczytywanie pliku i wyswietlPlik – prezentująca jego zawartości. Taka klasa łamie tą zasadę, gdyż posiada dwie niezależne funkcjonalności, dlatego trzeba wydzielić z niej osobne klasy, żeby ta zasada była spełniona. W programowaniu duże klasy jest trudnej rozwijać, utrzymywać i refaktoryzować. Budowanie tak ogromnych klas w późniejszych etapach programowania prowadzi do problemów, ponieważ ciężko je zmodyfikować, gdyż wpływają na dużą ilość funkcjonalności w programie. Natomiast tworząc wiele małych klas zwiększa się czytelność, łatwość rozbudowy i ogólnie mówiąc łatwość zarzadzania kodem projektu.

Zasada jednej odpowiedzialności oprócz klas tyczy się też interfejsów, jak również funkcji. Stosowanie jej w funkcjach jest podstawą do osiągnięcia czytelnego kodu. Funkcje, klasy i interfejsy powinno się rozbijać do jak najprostszych postaci, które z pewnością będą zwięzłe i będą odpowiadały za najlepiej pojedynczą operację w programie.

Przykład

Mamy stworzyć program do silnika w samochodzie. Mając na myśli zasady SOLID, zaczynamy od projektu interfejsu oraz klasy:

  1. <?php  
  2.   
  3. interface ISilnik  
  4. {  
  5.     public function zmniejszObroty();  
  6.     public function zwiekszObroty();  
  7.     public function aktualneObroty();  
  8. }  
  9.   
  10. class Silnik implements ISilnik  
  11. {  
  12.     public function aktualneObroty()  
  13.     {  
  14.         echo 'Aktualne obroty silnika <br>';  
  15.     }  
  16.   
  17.     public function  zwiekszObroty()  
  18.     {  
  19.         echo 'Zwiększenie obrotów silnika <br>';  
  20.     }  
  21.       
  22.     public function zmniejszObroty()  
  23.     {  
  24.         echo 'Zmniejszenie obrotów silnika <br>';  
  25.     }  
  26. }  
  27.   
  28. ?>  

Kod 1. Poprawny kod programu

Następnie postanawiamy zaprogramować przekładnie skrzyni biegów, więc udostępniamy funkcjonalność zmiany biegów w tym samym interfejsie:

  1. <?php  
  2.   
  3. interface ISilnik  
  4. {  
  5.     public function zmniejszObroty();  
  6.     public function zwiekszObroty();  
  7.     public function aktualneObroty();  
  8.   
  9.         //biegi  
  10.     public function biegWDol();  
  11.     public function biegWGore();  
  12. }  
  13.   
  14. ?>

Kod 2. Kod bez zastosowania pierwszej zasady SOLID

Na samym początku wydaje się, że jest wszystko w porządku, ponieważ silnik jest powiązany ze zmianami biegów. Jednak na pewno takie myślenie jest błędne. Spowodowaliśmy mnogość powodów, w których w przyszłości może być konieczność zmiany kodu należącego do jednej klasy (silnik i skrzynia biegów). Zasada jednej odpowiedzialności mówi, że powinien istnieć tylko jeden powód do zmiany klasy, a u nas mamy takich powodów więcej. Dlatego powinniśmy stworzyć dodatkowy interfejs oraz implementacje dla skrzyni biegów:

  1. <?php  
  2.   
  3. interface ISilnik  
  4. {  
  5.     public function zmniejszObroty();  
  6.     public function zwiekszObroty();  
  7.     public function aktualneObroty();  
  8. }  
  9.   
  10. interface ISkrzynia  
  11. {  
  12.     public function biegWDol();  
  13.     public function biegWGore();  
  14. }  
  15.   
  16. class Silnik implements ISilnik  
  17. {  
  18.     public function aktualneObroty()  
  19.     {  
  20.         echo 'Aktualne obroty silnika <br>';  
  21.     }  
  22.   
  23.     public function  zwiekszObroty()  
  24.     {  
  25.         echo 'Zwiększenie obrotów silnika <br>';  
  26.     }  
  27.       
  28.     public function zmniejszObroty()  
  29.     {  
  30.         echo 'Zmniejszenie obrotów silnika <br>';  
  31.     }  
  32. }  
  33.   
  34. class Skrzynia implements ISkrzynia  
  35. {  
  36.     public function biegWDol()  
  37.     {  
  38.         echo 'Zmiana biegu w dół <br>';  
  39.     }  
  40.   
  41.     public function  biegWGore()  
  42.     {  
  43.         echo 'Zmiana biegu w góre <br>';  
  44.     }  
  45. }  
  46.   
  47. ?> 

Kod 3. Kod z zastosowaniem pierwszej zasady SOLID

Podsumowanie

Powyżej widzimy poprawnie napisany program według pierwszej zasady SOLID. Zasadę tą wykorzystuje się w wielu aplikacjach webowych np. wykorzystano ją w aplikacji Personal Budget. Reasumując, z pewnością programowanie według tej praktyki, bardzo poprawia łatwość późniejszego utrzymania kodu i samego rozwoju. Dzięki temu przeglądając po jakimś czasie kod programu, łatwiej nam jest go analizować oraz wnioskować jakie komponenty należą do czego. Nie tworzymy przez to klas z dużą ilością kodu, które są ciężkie do odszyfrowania i zrozumienia.