Inwersja kontroli dotyczy przede wszystkim zarządzania zależnościami i dostarczania testowalnego kodu. Z klasycznego podejścia, jeśli klasa ma zależność, naturalną tendencją jest nadanie klasie, która ma zależność bezpośrednią kontrolę nad zarządzaniem jej zależnościami. Zwykle oznacza to, że klasa, która ma zależność, będzie "nowa" w swoich zależnościach w konstruktorze lub na żądanie w swoich metodach.
Inwersja kontroli polega na tym, że odwraca to, co tworzy zależności, eksternalizuje ten proces i wprowadza je do klasy, która ma zależność. Zwykle podmiot, który tworzy zależności, jest tym, co nazywamy kontenerem IoC, który odpowiada nie tylko za tworzenie i wstrzykiwanie zależności, ale także za zarządzanie ich życiem, określanie stylu życia (więcej o tym w sekundach), a także za oferowanie różnorodności innych możliwości. (Jest to oparte na Castle MicroKernel/Windsor, który jest moim ulubionym pojemnikiem IoC ... jego solidnie napisanym, bardzo funkcjonalnym i rozszerzalnym. Istnieją inne pojemniki IoC, które są prostsze, jeśli masz prostsze potrzeby, takie jak Ninject, Microsoft Unity i Spring.NET.)
Weź pod uwagę, że masz wewnętrzną aplikację, która może być używana zarówno w kontekście lokalnym, jak i zdalnym. W zależności od wykrywanych czynników aplikacja może wymagać załadowania "lokalnych" implementacji usług, aw innych przypadkach może być konieczne załadowanie "zdalnych" implementacji usług. Jeśli zastosujesz klasyczne podejście i stworzysz zależności bezpośrednio w klasie, która ma te zależności, wtedy ta klasa będzie zmuszona złamać dwie bardzo ważne zasady dotyczące tworzenia oprogramowania: Rozdzielanie obaw i Pojedyncza odpowiedzialność. Przekraczasz granice zainteresowania, ponieważ twoja klasa jest teraz zaniepokojona zarówno swoim wewnętrznym celem, jak i troską o ustalenie, które zależności powinny tworzyć i jak. Klasa jest teraz odpowiedzialna za wiele rzeczy, a nie za jedną rzecz, i ma wiele powodów do zmiany: wewnętrzne zmiany celu, proces tworzenia zmian zależności, sposób, w jaki znajduje się zależne zmiany, zależności, których zależności mogą wymagać itp.
Odwracając zarządzanie zależnościami, można ulepszyć architekturę systemu i utrzymywać SoC i SR (lub, być może, osiągnąć to, gdy poprzednio nie można było tego zrobić z powodu zależności). Ponieważ zewnętrzna jednostka, kontener IoC, teraz steruje w jaki sposób tworzone i wstrzykiwane są twoje zależności, możesz także uzyskać dodatkowe możliwości. Kontener może zarządzać cyklami życia twoich zależności, tworząc je i niszcząc w bardziej elastyczny sposób, który może poprawić efektywność. Zyskujesz także możliwość zarządzania stylami życia swoich obiektów. Jeśli masz typ zależności, który jest tworzony, używany i często zwracany, ale ma mały lub żaden stan (np. Fabryki), możesz dać mu wspólny styl życia, który powie kontenerowi, aby automatycznie utworzyć pula obiektów dla tego konkretnego typu zależności. Wiele stylów życia istnieje, a pojemnik taki jak Castle Windsor zwykle daje ci możliwość tworzenia własnych.
Lepsze pojemniki IoC, takie jak Castle Windsor, zapewniają również wiele możliwości rozbudowy. Domyślnie Windsor pozwala tworzyć instancje lokalnych typów. Możliwe jest tworzenie obiektów, które rozszerzają możliwości tworzenia typów Windsor, aby dynamicznie tworzyć proxy usług internetowych i hostów usług WCF w locie, w czasie wykonywania, eliminując potrzebę ręcznego lub statycznego tworzenia ich za pomocą narzędzi takich jak svcutil (to jest coś, co zrobiłem niedawno .) Istnieje wiele udogodnień umożliwiających obsługę IoC istniejących frameworków, takich jak NHibernate, ActiveRecord itp.
IoC wymusza na sobie styl kodowania, który zapewnia testowany kod jednostki. Jednym z kluczowych czynników umożliwiających testowanie jednostki kodu jest eksternalizacja zarządzania zależnościami. Bez możliwości zapewnienia alternatywnych (pozorowanych, zgaszonych itp.) Zależności, testowanie pojedynczej "jednostki" kodu w izolacji jest bardzo trudnym zadaniem, pozostawiając testowanie integracyjne jedynym alternatywnym stylem automatycznego testowania. Ponieważ IoC wymaga, aby twoje klasy akceptowały zależności za pomocą wtrysku (przez konstruktora, właściwość lub metodę), każda klasa jest zazwyczaj, jeśli nie zawsze, zredukowana do jednej odpowiedzialności odpowiednio wyodrębnionego koncernu i w pełni zależnych zależności.
IoC = lepsza architektura, większa spójność, ulepszona separacja problemów, klasy łatwiejsze do zredukowania do jednej odpowiedzialności, łatwo konfigurowalne i wymienne zależności (często bez konieczności ponownej kompilacji kodu), elastyczne style życia zależności i życie zarządzanie czasem i testowany kod jednostki. IoC to rodzaj stylu życia ... filozofia, podejście do rozwiązywania typowych problemów i spotkania z najlepszymi praktykami krytycznymi, takimi jak SoC i SR.
Nawet (a raczej szczególnie) z setkami różnych implementacji jednego interfejsu, IoC ma wiele do zaoferowania. Może trochę potrwać, zanim głowa zostanie w pełni owinięta, ale kiedy w pełni zrozumiesz, czym jest IoC i co może on dla ciebie zrobić, nigdy nie będziesz chciał robić nic w inny sposób (z wyjątkiem być może rozwoju systemów wbudowanych ...)
Celowo nie wspominałem o testowaniu, ponieważ wspomniał, że już używa DI. To wszystko, czego naprawdę trzeba kpić i testować. DI to strategia; Kontenery IoC ułatwiają tę strategię i ułatwiają implementację (zmniejszenie "kodu makaronu"). –
To prawdopodobnie powinno być zrobione jako komentarz do posta Jeremy'ego ... –