Wcześniej napisałem odpowiedź na temat zasady otwartej zamkniętej (OCP) vs. zasady substytucyjnej Liskowa (LSP) i obie te zasady bardzo się ze sobą wiążą, ale nadal są koncepcyjnie różne z niektórymi wymyślonymi przykładami posiadania jednego, ale nie drugiego. Z powodu tej odpowiedzi dotknę OCP tylko krótko i zanurzę się głębiej w DIP i co sprawia, że tykasz.
Spróbujmy przedyskutować, w jaki sposób OCP jest powiązany i różni się z Zasadą Inwersji Zależności (DIP), najpierw wyjaśniając różne zasady w pierwszej kolejności.
Zasada inwersji zależności
Czytając Zasady OOD wuja Boba, przekonasz się, że DIP stwierdza, co następuje:
Zależy od abstrakcji, a nie od konkrecji.
Abstrakcja w Javie jest po prostu uzyskiwana za pomocą słów kluczowych interface
i abstract
, co oznacza, że masz „kontrakt” na pewną jednostkę oprogramowania, której musi przestrzegać kod. Niektóre języki programowania nie mają możliwości jawnego ustawiania zachowań kodu, więc abstrakcje muszą być wykonywane w bardziej ręczny sposób, niż kompilator pomaga w egzekwowaniu umowy. Np. W C ++ masz klasy z metodami wirtualnymi, a w dynamicznych językach programowania, takich jak Javascript, musisz upewnić się, że używasz obiektów w ten sam sposób (chociaż w przypadku Javascript został on rozszerzony w TypeScript, który dodaje system typów, aby ci pomóc z pisaniem umów weryfikowanych przez kompilator).
Nazwa zawiera termin „inwersja”, ponieważ tradycyjnie (wiesz w dawnych wiekach programowania) pisałeś struktury oprogramowania, które miały moduły wyższego poziomu w zależności od modułów niskiego poziomu. Np. Sensowne było mieć ButtonAtKitchen
dane wejściowe obsługi dla a KitchenLamp1
i KitchenLamp2
. Niestety, dzięki temu oprogramowanie było o wiele bardziej szczegółowe, niż trzeba, a wykres obiektowy wyglądałby tak:
Kiedy więc uczynisz oprogramowanie bardziej ogólnym, dodając „umowy”. Zauważ, jak strzałki na wykresie obiektowym „odwracają” kierunek. Że lampy kuchenne są teraz zależne od Button
. Innymi słowy, szczegóły zależą teraz od abstrakcji, a nie na odwrót.
Mamy zatem bardziej ogólną definicję DIP, szczegółowo opisaną również w oryginalnym artykule DIP autorstwa wujka Boba .
A. Moduły wysokiego poziomu nie powinny zależeć od modułów niskiego poziomu. Oba powinny zależeć od abstrakcji. B. Abstrakcje nie powinny zależeć od szczegółów. Szczegóły powinny zależeć od abstrakcji.
Zasada otwarta-zamknięta
Kontynuując zasady wuja Boba, przekonasz się, że OCP stwierdza, co następuje:
Powinieneś być w stanie przedłużyć zachowanie klasy, nie modyfikując go.
Jednym z przykładów osiągnięcia tego jest zastosowanie wzorca strategii, w którym Context
klasa jest zamknięta dla modyfikacji (tj. Nie można w ogóle zmienić jej kodu wewnętrznego), ale jest również otwarta na rozszerzenie poprzez zależności zależne (tj. Klasy strategii).
W bardziej ogólnym znaczeniu każdy moduł jest zbudowany tak, aby był rozszerzalny poprzez swoje punkty rozszerzeń.
OCP jest podobny do DIP, prawda?
Nie , niezupełnie.
Chociaż obaj dyskutują o abstrakcjach, różnią się koncepcyjnie. Obie zasady dotyczą różnych kontekstów, OCP dla jednego konkretnego modułu i DIP dla kilku modułów. Możesz osiągnąć oba w tym samym czasie, co większość wzorców projektowych Gang of Four, ale nadal możesz odejść od ścieżki.
We wspomnianym powyżej przykładzie DIP, z przyciskiem i lampami kuchennymi, żadna z lamp kuchennych nie jest rozszerzalna (ani obecnie nie ma żadnych wymagań wyjaśniających, że muszą być). Projekt łamie OCP, ale podąża za DIP .
Odwrotnym (i wymyślonym) przykładem może być lampa kuchenna, którą można rozszerzać (z punktem przedłużenia jest czymś w rodzaju a LampShade
), ale przycisk jest nadal zależny od lamp . Jest to łamanie DIP ale następuje OCP .
Nie martw się, to się zdarza
W rzeczywistości jest to coś, co często zdarza się w kodzie produkcyjnym, że jego część może złamać zasadę. W większych systemach oprogramowania (tj. Cokolwiek większego niż powyższe przykłady) możesz złamać jedną zasadę, ale zachowując drugą zwykle, ponieważ musisz zachować prosty kod. Moim zdaniem jest to w porządku dla małych i niezależnych modułów, ponieważ są one w kontekście związanym z zasadą pojedynczej odpowiedzialności (SRP).
Po jakiś moduł komplikuje chociaż najprawdopodobniej trzeba spojrzeć na to z wszystkimi zasadami zawartymi w umyśle i przeprojektowanie czy byłaby to do pewnego znanego wzorca.