S.O.L.I.D.ne programowanie – część 0, czyli wstęp
S.O.L.I.D.ne programowanie – część 1, czyli monogamia

Witam w drugiej części cyklu „S.O.L.I.D.ne programowanie”, poświęconego zasadom S.O.L.I.D. Dziś przyjrzymy się bliżej Open-Close Principle (OCP).

Ciężko było mi wyszukać jakiś elegancki przykład no i czasu było mało, ale przepraszam za opóźnienia. Jedziemy.

Drogie panie otwieram nasz kram…

Dobry kod obiektowy powinien cechować się dużą elastycznością. Elastyczność to przede wszystkim umiejętność szybkiego dostosowania się do nowych wymagań. Szybkie dostosowanie oznacza przede wszystkim małą liczbę zmian. Wynika to z faktu, że zmieniany kod trzeba testować. W dodatku zmiany wpływają na inne elementy aplikacji i je też trzeba testować. Zasada OCP mówi:

SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION.

Jako, że zmiany są jedyną pewną i niezmienną rzeczą z jaka mamy do czynienia w programowaniu, więc kod, który nie umie się zmieniać jest do wyrzucenia. Sama zasada jest przewrotna, bo cóż oznacza otwartość na zmiany i jednoczesna niemożliwość modyfikacji?
Ta przewrotność jest jednocześnie pewną filozofią. Wraz z kolejnymi zasadami odkryjemy, że celem S.O.L.I.D. jest takie konstruowanie kodu by zmiany w jego działaniu nie wpływały na kod klienta.
OCP można realizować w kilku aspektach. Przyjrzymy się wszystkim po kolei. Każdy z nich dotyczy innego zagadnienia, ale wszystkie należą do zagadnień związanych z organizacją kodu.

Dziedziczenie nie jest złe

Od wielu lat wbija się do głowy kolejnym pokoleniom programistów Java, że nie powinni używać dziedziczenia, ale implementować interfejsy. Jest to o tyle słuszne, że mało kto potrafi zaproponować odpowiedni sposób dziedziczenia. Przez sposób rozumiem tu zarówno realizację dziedziczenia w aplikacji jak i motywację i uzasadnienie tejże.
Powróćmy do naszego przykładu z pierwszej części. Przedstawiony tam przykład modemu będzie nam służył w tym artykule. Załóżmy, że chcemy rozszerzyć funkcjonalność modemu o obsługę WiFi. Co powinniśmy zatem zrobić? Najprościej jest zmienić tak implementację by możliwe było przyjmowanie połączeń nowym kanałem. Zmiany tej dokonujemy przez stworzenie dekoratora, który otoczy standardową implementację i doda odpowiednią funkcjonalność. To jest dobre OCP. Nie zmieniamy już gotowego kodu, a tylko nieinwazyjnie dodajemy do niego odpowiednie funkcjonalności.
Złym OCP będzie grzebanie bezpośrednio w kodzie, ale najgorszym będzie pisanie wszystkiego od nowa.
Na tym poziomie mówimy o OCP w odniesieniu do funkcjonalności kodu. Przyjrzyjmy się teraz samym obiektom.

Gettery i Settery to nie hermetyzacja

Co tu dużo mówić, jeżeli w naszych obiektach wszystkie pola mają metody ustawiające to nie możemy mówić o OCP. Kod tego typu nie jest zamknięty na modyfikacje ponieważ w pełni został ujawniony. Publikować należy zatem tylko to co jest naprawdę niezbędne i robimy to w sposób bezpieczny wielowątkowo.

Pakiet

Poruszyliśmy już temat funkcjonalności kodu i API klasy. Ostatnim zagadnieniem jest odpowiednie publikowanie modułów. Zazwyczaj moduły mają bardzo dużo klas publicznych. OCP jest przeciwnikiem publikowania elementów zmiennych. Prawidłowo skonstruowany moduł powinien umożliwiać jego rozszerzenie w dowolnym punkcie, ale bez możliwości zmiany kodu modułu. Oznacza to, że należy ograniczyć możliwość takiego rozszerzania klas, które realizują zadania wewnątrz modułu, że ingerujemy w moduł np. zmianiając konfigurację fabryk.

Podsumowanie

OCP jest bardzo dziwną zasadą, która nie jest oczywista dopóki czegoś nie popsujemy. Zapraszam zatem do dyskusji o różnych aspektach OCP.

co ja mam dziś z tymi aspektami