2009-05-23 22 views
13

Używam intensywnie iniekcji zależności przez parametry i konstruktory. Rozumiem zasadę do tego stopnia i jestem z niej zadowolony. W moich dużych projektach kończę z wprowadzeniem zbyt wielu zależności (wszystko, co trafia w podwójne liczby, wydaje się duże - podoba mi się określenie "kod makaronowy").Czy ktoś może mi wyjaśnić, jak używać pojemników IOC?

Jako takie, rozważałem pojemniki IOC. Przeczytałem kilka artykułów na ich temat i do tej pory nie dostrzegłem korzyści. Widzę, jak pomaga w wysyłaniu grup powiązanych obiektów lub w powtarzaniu tego samego typu. Nie jestem pewien, w jaki sposób pomogliby mi w moich projektach, w których mogę mieć ponad sto klas implementujących ten sam interfejs i gdzie używam ich wszystkich w różnych zamówieniach.

Czy ktokolwiek może wskazać mi dobre artykuły, które opisują nie tylko koncepcje kontenerów IOC (najlepiej bez szczególnego hantowania), ale również pokazują szczegółowo, w jaki sposób zyskują na tym projekcie i jak one pasują w zakresie dużej architektury?

Mam nadzieję, że zobaczę jakieś rzeczy niezwiązane z językiem, ale moim preferowanym językiem jest C#.

Odpowiedz

1

mam żadnych powiązań, ale może dostarczyć przykład:

masz kontroler internetową, która musi wywołać usługę, która ma warstwę dostępu do danych.

Teraz przyjmuję to w swoim kodzie, że konstruujesz te obiekty w czasie kompilacji. Używasz przyzwoitego wzorca projektowego, ale jeśli kiedykolwiek będziesz musiał zmienić implementację powiedzmy dao, musisz wejść do swojego kodu i usunąć kod, który ustawia tę zależność w górę, rekompiluj/przetestuj/wdróż. Ale jeśli użyjesz kontenera IOC, po prostu zmienisz klasę w konfiguracji i zrestartujesz aplikację.

3

Jeśli masz ponad sto klas realizujących wspólny interfejs, MKOl nie pomoże bardzo, trzeba fabrykę . W ten sposób, można wykonać następujące czynności:

public interface IMyInterface{ 
    //... 
} 

public class Factory{ 

    public static IMyInterface GetObject(string param){ 
     // param is a parameter that will help the Factory decide what object to return 
     // (that is only an example, there may not be any parameter at all) 
    } 
} 

//... 
// You do not depend on a particular implementation here 
IMyInterface obj = Factory.GetObject("some param"); 

w fabryce, można użyć kontenera IoC odzyskać przedmioty, jeśli chcesz, ale musisz zarejestrować każdą z klas, które implementują dany interfejs i powiąż go z niektórymi kluczami (i użyj tych kluczy jako parametrów w metodzie GetObject()).

IoC jest szczególnie przydatna, gdy trzeba pobrać obiektów, które implementują różne interfejsy:

IMyInteface myObject = Container.GetObject<IMyInterface>(); 
IMyOtherInterface myOtherObject Container.GetObject<IMyOtherInterface>(); 
ISomeOtherInterface someOtherObject = Container.GetObject<ISomeOtherInterface>(); 

zobaczyć? Tylko jeden obiekt, aby uzyskać kilka różnych obiektów typu i bez kluczy (same interfejsy są kluczami). Jeśli potrzebujesz obiektu, aby uzyskać kilka różnych obiektów, ale wszystkie implementujące ten sam interfejs, IoC nie pomoże ci bardzo.

3

W ciągu ostatnich kilku tygodni pogrążyłem się w zastrzyku polegającym na uzależnieniu od pełnej inwersji kontroli w Castle, więc rozumiem, skąd pochodzi twoje pytanie.

Kilka powodów dlaczego nie chciałbym użyć kontenera IoC:

  1. Jest to mały projekt, który nie będzie się rozwijać tak dużo. Jeśli istnieje relacja 1: 1 między konstruktorami a wywołaniami do tych konstruktorów, użycie kontenera IOC nie zmniejszy ilości kodu, który muszę napisać. Nie łamiesz "nie powtarzaj się", dopóki nie pokażesz sobie skopiowania i wklejenia tego samego "var myObject = new MyClass (someInjectedDependency)" po raz drugi.

  2. Być może będę musiał dostosować istniejący kod, aby ułatwić ładowanie do kontenerów IOC. Prawdopodobnie nie jest to konieczne, dopóki nie przejdziesz do kilku ciekawszych funkcji programowania zorientowanych na Aspekt, ale jeśli zapomnisz, że metoda jest wirtualna, odciąłeś tę klasę metody i nie implementujesz interfejsu, a ty " czują się niewygodnie, dokonując tych zmian z powodu istniejących zależności, a następnie zmiana nie jest tak atrakcyjna.

  3. Dodaje dodatkową zewnętrzną zależność do mojego projektu - i do mojego zespołu. Mogę przekonać resztę mojego zespołu, że konstruowanie ich kodu, aby pozwolić DI jest spuchnięty, ale jestem obecnie jedynym, który wie, jak pracować z Zamkiem. W przypadku mniejszych, mniej skomplikowanych projektów nie będzie to problemem. W przypadku większych projektów (które, jak na ironię, przyniosłyby najwięcej korzyści z kontenerów IOC), jeśli nie będę w stanie ewangelizować z wykorzystaniem kontenera IOC wystarczająco dobrze, samodzielna praca w moim zespole nikomu nie pomoże.

Niektóre z powodów, dla których nie chciałabym wrócić do zwykłego DI:

  1. mogę dodać lub zabrać zalogowaniu do dowolnej liczby moich klas, bez dodawania jakichkolwiek instrukcja śledzenia lub rejestrowania. Możliwość przeplatania moich zajęć z dodatkową funkcjonalnością bez zmiany tych klas jest niezwykle skuteczna. Na przykład:

    Logging: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Transakcje: http://www.codeproject.com/KB/architecture/introducingcastle.aspx (skip dół do sekcji Transaction)

  2. Zamek, przynajmniej jest tak pomocne przy podłączaniu się zajęcia na zależnościach, że byłoby bolesne wrócić.

Na przykład brakuje zależność z zamkiem:

„Nie można utworzyć elementu«MojaKlasa»jako ma zależności zostać spełnione Service jest oczekiwanie na następujących zależności.:

Usługi: - Usługa IMyService, która nie została zarejestrowana."

Brakujące zależność bez Castle:

Odwołanie do obiektu nie jest ustawiony na wystąpienie obiektu

szarym końcu: zdolność do wymiany wstrzyknięte usługi w czasie wykonywania przez edytowanie pliku Xml. Moją percepcją jest to, że jest to najbardziej napięta funkcja, ale widzę ją tylko jako lukru na torcie. Wolę podłączyć wszystkie moje usługi w kodzie, ale jestem pewien, że napotkam bóle głowy w przyszłości, gdzie mój umysł zostanie zmieniony na tym

Przyznam, że - będąc początkującym dla IOC i Castle - prawdopodobnie tylko drapię powierzchnię, ale do tej pory naprawdę podoba mi się to, co widzę. Czuję, że ostatnie kilka projektów, które zbudowałem, jest naprawdę zdolnych do reagowania na nieprzewidywalne zmiany, które pojawiają się z dnia na dzień w mojej firmie, uczucie, jakiego nigdy wcześniej nie doświadczyłem.

1

Jeremy Frey pomija jeden z największych powodów używania pojemnika z IOC: ułatwia kodyfikowanie i testowanie kodu.

Zachęcanie do korzystania z interfejsów ma wiele innych fajnych zalet: lepsze nawarstwianie, łatwiejsze dynamiczne generowanie proxy dla takich rzeczy, jak transakcje deklaratywne, programowanie aspektowe i zdalne.

Jeśli uważasz, że IOC jest dobry tylko do zamiany połączeń na "nowy", nie dostaniesz go.

+0

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"). –

+1

To prawdopodobnie powinno być zrobione jako komentarz do posta Jeremy'ego ... –

13

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 ...)

+2

Bardzo ładna odpowiedź. – Klinger

+0

Dziękuję za to wyjaśnienie !!! – John

0

Kontrole IoC zwykle wykonują zastrzyki uzależniające, które w niektórych projektach nie stanowią wielkiego problemu, ale niektóre z ram zapewniających kontenery IoC oferują inne usługi, dzięki którym warto z nich korzystać. Zamek na przykład ma pełną listę usług oprócz kontenera IoC. Dynamic proxy, zarządzanie transakcjami i udogodnienia NHibernate to tylko niektóre z nich. Następnie myślę, że należy rozważyć contianers IoC jako część ramy aplikacji.

Oto dlaczego używam kontenera IoC: testy jednostkowe 1.Writing będzie łatwiejsze .Actually piszesz różne konfiguracje, aby robić różne rzeczy 2.Adding różnych wtyczek dla różnych scenariuszy (dla różnych klientów, na przykład) 3. Przechwytywanie klas w celu dodania różnych aspektów do naszego kodu. 4. Od kiedy używamy NHibernate, zarządzanie transakcjami i udogodnienia NHibernate Castle są bardzo pomocne w rozwijaniu i utrzymywaniu naszego kodu. To tak, jak każdy aspekt techniczny naszej aplikacji jest obsługiwany za pomocą struktury aplikacji i mamy czas, aby pomyśleć o tym, czego naprawdę chcą klienci.

Powiązane problemy