Rozważać:
public class CtorInjectionExample
{
public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn)
{
this._someRepository = SomeRepositoryIn;
this._otherRepository = OtherRepositoryIn;
}
public void SomeMethod()
{
//use this._someRepository
}
public void OtherMethod()
{
//use this._otherRepository
}
}
przeciwko:
public class MethodInjectionExample
{
public MethodInjectionExample()
{
}
public void SomeMethod(ISomeRepository SomeRepositoryIn)
{
//use SomeRepositoryIn
}
public void OtherMethod(IOtherRepository OtherRepositoryIn)
{
//use OtherRepositoryIn
}
}
Podczas gdy wstrzykiwanie Ctor utrudnia rozszerzenie (każdy kod wywołujący ctor będzie wymagał aktualizacji po dodaniu nowych zależności), a wstrzykiwanie na poziomie metody wydaje się być bardziej enkapsulowane z zależności na poziomie klasy i nie mogę znaleźć żadnych innych argumentów za / przeciw tym podejściom .
Czy istnieje ostateczne podejście do wstrzyknięcia?
(Uwaga: szukałem informacji na ten temat i starałem się, aby pytanie było obiektywne).
Odpowiedzi:
To zależy, jeśli wstrzyknięty obiekt jest używany przez więcej niż jedną metodę w klasie, a wstrzyknięcie do niego każdej metody nie ma sensu, musisz rozwiązać zależności dla każdego wywołania metody, ale jeśli zależność jest używana tylko przez jedna metoda wstrzyknięta do konstruktora nie jest dobra, ale ponieważ alokujesz zasoby, których nigdy nie można użyć.
źródło
Po pierwsze, porozmawiajmy o: „Każdy kod wywołujący ctor będzie wymagał aktualizacji po dodaniu nowych zależności”; Dla jasności, jeśli robisz wstrzykiwanie zależności i masz jakiś kod wywołujący new () na obiekcie z zależnościami, robisz to źle .
Twój kontener DI powinien być w stanie wstrzyknąć wszystkie odpowiednie zależności, więc nie musisz się martwić o zmianę podpisu konstruktora, aby ten argument tak naprawdę się nie utrzymywał.
Jeśli chodzi o ideę wtrysku według metody vs. dla klasy, istnieją dwa główne problemy z wtryskiem według metody.
Jednym z problemów jest to, że metody twojej klasy powinny współdzielić zależności, to jeden ze sposobów, aby upewnić się, że twoje klasy są skutecznie rozdzielone, jeśli zobaczysz klasę z dużą liczbą zależności (prawdopodobnie więcej niż 4-5), to ta klasa jest głównym kandydatem za refaktoryzację na dwie klasy.
Kolejny problem polega na tym, że aby „wstrzyknąć” zależności dla poszczególnych metod, należy przekazać je do wywołania metody. Oznacza to, że będziesz musiał rozwiązać zależności przed wywołaniem metody, więc najprawdopodobniej otrzymasz kilka takich kodów:
Powiedzmy, że wywołasz tę metodę w 10 miejscach w swojej aplikacji: będziesz mieć 10 takich fragmentów. Następnie powiedz, że musisz dodać kolejną zależność do DoStuff (): będziesz musiał zmienić ten fragment kodu 10 razy (lub owinąć go metodą, w którym to przypadku po prostu replikujesz zachowanie DI ręcznie, co jest marnotrawstwem czasu).
Zatem to, co właściwie zrobiłeś, sprawiło, że twoje klasy korzystające z DI zdają sobie sprawę z własnego kontenera DI, co jest zasadniczo złym pomysłem , ponieważ bardzo szybko prowadzi do trudnego do utrzymania projektu.
Porównaj to z iniekcją konstruktora; W iniekcji konstruktora nie jesteś przywiązany do konkretnego kontenera DI i nigdy nie jesteś bezpośrednio odpowiedzialny za wypełnianie zależności swoich klas, więc utrzymanie jest dość wolne od bólu głowy.
Wydaje mi się, że próbujesz zastosować IoC do klasy zawierającej kilka niepowiązanych metod pomocniczych, podczas gdy lepiej byłoby podzielić klasę pomocniczą na kilka klas usług na podstawie użycia, a następnie użyć pomocnika do delegowania połączenia. To wciąż nie jest świetne podejście (pomocnik klasyfikowany metodami, które robią coś bardziej złożonego niż tylko radzenie sobie z argumentami, które są do nich przekazywane, są zwykle po prostu źle napisanymi klasami usług), ale przynajmniej utrzyma twój projekt trochę czystszy .
(Zauważyłem wcześniej podejście, które sugerujesz, i to był bardzo zły pomysł, którego odtąd nie powtarzałem. Okazało się, że próbowałem wydzielić klasy, które tak naprawdę nie musiały być oddzielone, i ostatecznie skończyłem z zestawem interfejsów, w których każde wywołanie metody wymagało prawie stałego wyboru innych interfejsów. Utrzymanie tego było koszmarem).
źródło
"if you're doing dependency injection and you have any code calling new() on an object with dependencies, you're doing it wrong."
Jeśli testujesz jednostkowo metodę w klasie, musisz ją utworzyć lub czy używasz DI do utworzenia kodu w trakcie testowania?"any code calling the ctor will need updating"
, kiedy mówię , że mój kod produkcyjny nie wywołuje lekarzy. Z tych powodów.Istnieją różne rodzaje inwersji kontroli , a twoje pytanie proponuje tylko dwa (możesz również użyć fabryki, aby wprowadzić zależność).
Odpowiedź brzmi: zależy to od potrzeby. Czasami lepiej jest używać jednego rodzaju, a innego innego.
Osobiście lubię wtryskiwacze konstruktorów, ponieważ konstruktor służy do pełnej inicjalizacji obiektu. Późniejsze wywołanie setera powoduje, że obiekt nie jest w pełni skonstruowany.
źródło
Przegapiłeś tę, która przynajmniej dla mnie jest najbardziej elastyczna - zastrzyk nieruchomości. Używam Castle / Windsor i wszystko, co muszę zrobić, to dodać nową właściwość auto do mojej klasy i otrzymuję wstrzyknięty obiekt bez żadnych problemów i bez zerwania interfejsów.
źródło