Ten skrót już od kilku lat robi furorę w internecie oraz...podczas rozmów kwalifikacyjnych. Faktycznie to bardzo ważne, aby trzymać się zasad, które
opisuje ten akronim. Co więc oznacza SOLID? Nie jest to wzorzec projektowy sam w sobie. Akronim opisuje zbiór reguł, których powinniśmy się trzymać podczas tworzenia kodu.
Rozbijamy go na poszczególne litery, które tłumaczymy z angielskiego tak:
-
S - Single responsibility principle - Zasada jednej odpowiedzialności
Klasy powinny mieć ściśle określoną odpowiedzialność. Nigdy nie powinien istnieć więcej niż jeden powód modyfikacji klasy.
Przykład
W przypadku gdy klasa odpowiada za tworzenie obiektów na podstawie zadanego interfejsu (fabryka), nie powinna zajmować się niczym innym.
Nie może nagle stać się miejscem aktualizacji danych, czy też wykonawcą innych zadań niezwiązanych z jej specjalizacją (jakim jest tworzenie obiektów danego interfejsu).
-
O - Open/closed principle - Zasada otwartości na rozszerzenie i zakmniętości na modyfikacje
Kod powinien być tak napisany, by w przypadku rozwoju systemu i pojawiających się kolejnych wymagań biznesowych, nie trzeba było zmieniać istniejącego kodu.
Ma on być otwarty na rozszerzanie i dodawanie nowych "klocków". Wymaganie to zmusza nas do dokładnego przemyślenia realizowanych zadań i wprowadzenia od początku na tyle
ogólnych rozwiązań, by były one przygotowane pod dalszą rozbudowę.
Przykład
Implementując eksporter plików przygotowujemy metody, które będą abstrakcyjne i zapewnią możliwość wprowadzania kolejnych implementacji w postaci nowych
klas w przyszłości. Każda taka klasa będzie dostarczać własną implementację eksportu. Inaczej będzie wyglądało wykonywanie eksportu do pliku csv, a inaczej do pliku xls, niemniej
wszystkie eksporty będą posiadały ogólny zbiór podobnych zadań, takich jak pobranie danych, ich przetworzenie oraz eksport do pliku. Wspólne dla wszystkich będą pewne cechy, na przykład
nazwa pliku, czy jego rozszerzenie.
Nawet jeśli w pierwszej fazie projektu musimy przygotować eksport tylko do pliku csv, warto wprowadzić ogólny mechanizm eksportu, a implementacje metod
dostarczyć w osobnych klasach. Jeśli nagle pojawi się wymaganie dodania eksportu xls, wówczas do wykonania pozostanie nam tylko przygotowanie klasy dedykowanej temu typowi eksportu.
Nic nie zmieniamy w kontekście samego procesu (jego uruchomienia, obsługi błędów, czy obsługi zakończenia). Wszelkie zmiany nie mają również wpływu na kod eksportu csv (nie musimy go zmieniać).
-
L - Liskov substitution principle - Zasada podstawienia Liskova
Tworząc kod powinniśmy go budować tak, aby zawsze działał zarówno dla samej klasy bazowej, jak i każdej implementacji.
Przykład
W przypadku wspomnianego eksportera możemy zrealizować nasz szczytny cel wydzielenia klasy bazowej, a następnie dostarczenia kolejnych implementacji eksportu w postaci niezależnych klas,
ale jeśli nie stworzymy odpowiednio wartościowych metod operujących na każdej z klas eksportujących, wówczas i tak możemy nie spełnić zasady podstawienia.
Na przykład jeśli w trakcie tworzenia klasy menedżera plików założymy, że będzie on działał dla każdej klasy rozszerzającej klasę bazową, ale jednocześnie w kodzie takiego menedżera
wprowadzimy operacje specyficzne tylko dla plików xls, wtedy uruchomienie metody dla innych implementacji (na przykład dla pliku csv) nie zadziała lub wygeneruje błąd.
I to znaczy, że nasz kod nie spełnia w tym miejscu zasady podstawienia Liskova.
-
I - Interface segregation principle - Zasada segregacji interfejsów
Każdy interfejs powinien mieć wąski zakres specjalizacji. Dodatkowo powinny one być zwięzłe tematycznie, tak by maksymalnie ograniczyć występowanie pustych implementacji metod.
Przykład
Wprowdzamy do naszego eksportera interfejs przygotowujący raport zawierający prostą statystykę na temat wyeksportowanych elementów.
Prawdopodobne wystarczy nam interfejs zawierający metody addReportData i createReport. Wtedy każdy eksporter implementując taki interfejs ma
do dostarczenia zwięzłą listę metod. Nie ma tutaj metod nadmiarowych. Każda klasa zaimplementuje obie metody.
Natomiast, gdybyśmy chcieli do takiego interfejsu dodać jeszcze metodę w stylu writeReportToFile, to mogłoby się okazać, że nie wszystkie klasy jej potrzebują.
O ile każda z nich musi dostarczyć implementację tworzenia raportu, o tyle niektóre mogą na przykład "chcieć" zapisać wynik takiego raportu do bazy, albo wysłać taki raport za pomocą żądania REST.
Wtedy metoda writeReportToFile pozostałaby pusta, a w samym interfejsie należałoby dodać metody w stylu writeReportToDB lub sendReportToExternalSource.
Te metody byłyby jednak puste w przypadku klasy dostarczającej zapis do pliku.
Takich problemów staramy sie unikać. Segregujemy interfejsy i tworzymy osobny interfejs, nawet z jedną metodą generyczną definiującą możliwe formy zapisu raportu -
na przykład storeResults.
-
D - Dependency inversion principle - Zasada odwrócenia zależności
Wysokopoziomowe moduły (bardziej abstrakcyjne) nie powinny zależeć od modułów niskopoziomowych (bardziej specjalizowanych).
Innymi słowy, abstrakacja nie powinna zależeć od implementacji.
Przykład
Co to oznacza w przypadku naszego przykładu? Jeśli po skonstruowaniu klasy bazowej z metodą export dodamy kilka klas dziedziczących, implementujących tę metodę, to wszystkie operacje
doszczegóławiające export (czyli konkretne wykonanie exportu) powinny się odbywać w klasach dedykowanych każdemu z typów pliku.
Jeśli nagle zaczniemy wprowadzać w metodzie export w klasie bazowej kod w stylu instrukcji if sprawdzającej czy mamy do czynienia z implementacją typu XlsExport czy CsvExport
i tam dodamy wykonanie operacji zależnej od typu klasy, wówczas abstrakcyjna klasa bazowa zacznie zależeć od implementacji i nasza zasada nie będzie spełniona.
Tak naprawdę wielu programistów - często nawet nie do końca świadomie - stosuje się zwykle do części z wymienionych zasad, niemniej ważne jest, aby stosować się do nich wszystkich. Wtedy kod będzie dobrej jakości
i nie sprawi większych problemów kolejnym programistom, którzy będą go rozwijać w przyszłości. Tworzenie kodu w ten sposób jest oznaką profesjonalizmu i na pewno zostanie docenione przez
innych członków zespołu.
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Czy informacje, które otrzymałeś, były pomocne?
Jeśli tak, zapraszam Cię do podarowania mi kawy.