Zasada otwartego zamknięcia (OCP) a zasada inwersji zależności (DIP)

12

Próbowałem zrozumieć różnicę między otwartą zasadą zamkniętą (OCP) a zasadą odwrócenia zależności (DIP).

Na podstawie badań, które przeprowadziłem do tej pory w Internecie, doszedłem do wniosku, że „DIP jest jedną z opcji, dzięki której możemy osiągnąć OCP”.

Mam rację?

Czy możesz podać mi przykład, który nie podąża za DIP, ale podąża za OCP?

Jitendar
źródło

Odpowiedzi:

16

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 interfacei 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ć ButtonAtKitchendane wejściowe obsługi dla a KitchenLamp1i KitchenLamp2. Niestety, dzięki temu oprogramowanie było o wiele bardziej szczegółowe, niż trzeba, a wykres obiektowy wyglądałby tak:

ButtonAtKitchen obsługuje KitchenLamp1 i KitchenLamp2

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.

KitchenButton ma teraz abstrakcję IButton, od której zależą lampy kuchenne

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 Contextklasa 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ń.

Moduł z punktami rozszerzenia

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.

Łup
źródło