Dzisiaj artykuł o wstrzykiwaniu zależności. W tworzonej przeze mnie aplikacji CyberHome stosuję wstrzykiwanie zależności za pomocą AutoFac’a. Na wstępie zastanowimy się po co to na w ogóle… Zapraszam do lektury.
Każda poważniejsza aplikacja w obiektowym języku programowania powinna implementować zasadę odwróconego sterowania (IoC), a jej poszczególne modułu powinny być luźno powiązane (loose coupling).
Często z IoC utożsamiamy DI (wstrzykiwanie zależności), podczas gdy DI to najpopularniejsza realizacji IoC; nie będę się produkował ponieważ Wikipedia bardzo trafnie to opisuje:
DI silnie preferuje zewnętrzne tworzenie połączeń (zależności) pomiędzy komponentami oprogramowania (np. asocjacje w klasach), nad zlecaniem tworzenia zależności im samym.
Jest to wzorzec, w którym odpowiedzialność za tworzenie obiektów i łączenie jest przeniesiona z obiektów do fabryki (np. kontenera IoC).
Na żądanie kodu fabryka tworzy obiekt, lub udostępnia obiekt z puli obiektów, ustawiając mu powiązania z innymi obiektami (np. wstrzykiwanie konstruktorem –- Constructor Injection, wstrzykiwanie mutatorami – Setter Injection, użycie interfejsu Interface Injection lub w mieszany sposób).
DI jest więc realizacją „odwrócenia sterowania” w sensie tworzenia i wiązania obiektów.
Jakie zalety wynikają ze stosowania odwróconego sterowania:
- Wymusza tworzenie dobrze zorganizowanego, modułowego kodu, o ściśle przypisanych zadaniach.
- Kod podlega dużo łatwiejszemu testowaniu (tylko krok dzieli nas od TDD).
- Kod jest luźno powiązany.
A są jakieś wady..?
Wad jest niewiele, przede wszystkim jeśli nie mamy doświadczenia łatwo jest popłynąć i zbyt mocno „zgranulować” kod .
Jeśli skorzystamy z kontenera IoC (a skorzystamy na pewno! :)) tracimy część kontroli nad tym co dzieje się w aplikacji – kontener niektóre czynności (np. tworzenie obiektów, instancjonowanie ich) wykonuje za nas. Oczywiście – jest to zgodne z naszym oczekiwaniem.
Najprostszy przykład DI
Wyróżniamy kilka sposobów wstrzykiwania instancji jednej klasy w drugą.
Najprostszym z nich jest Constructor Injection (dokładny opis tutaj):
class AppPoolWatcher { INofificationAction action = null; public AppPoolWatcher(INofificationAction concreteImplementation) { this.action = concreteImplementation; } public void Notify(string message) { action.ActOnNotification(message); } }
Jak widać konstruktor klasy AppPoolWatcher oczekuje jako argumentu instancji klasy implementującej interfejs INotificationAction. Interfejs ten wymusza implementację metody ActOnNotification(string).
Obie klasy będą więc z sobą luźno powiązane, autor AppPoolWatcher wie, że otrzyma działającą instancję klasy, na z której będzie mógł wywołać metodę ActionOnNotNotification. Nie uzależniamy ściśle jednej klasy od drugiej.
EventLogWriter writer = new EventLogWriter(); AppPoolWatcher watcher = new AppPoolWatcher(writer); watcher.Notify("Sample message to log");
Powyżej użycie w kodzie: tworzymy klasę EventLogWriter implementująca interfejs INotificationAction.
Tworzymy klasę AppPoolWatcher , jako argument konstruktora przekazujemy instancje utworzonej w poprzednim kroku klasy.
Następnie możemy wywołać metodę Notify narzuconą przez INotificationAction. Działa! 🙂
AutoFac zrobi całą robotę za nas! Opowiem o tym w kolejnym artykule. Pokażę również jak go używam w moim programie.
Artykuł w ukazuje się w ramach projektu CyberHome tworzonego w ramach akcji DajSięPoznać.
Czekam na następny artykuł o AutoFac 🙂
Już niebawem! 🙂
Drugą część szlak trafił 🙂
Tak, wiem, szlag nie szlak.
Drugą część szlag trafił 🙂