Uważam, że moi konstruktorzy zaczynają wyglądać tak:
public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )
z ciągle rosnącą listą parametrów. Ponieważ „Kontener” jest kontenerem do wstrzykiwania zależności, dlaczego nie mogę tego po prostu zrobić:
public MyClass(Container con)
dla każdej klasy? Jakie są wady? Jeśli to zrobię, wydaje mi się, że używam gloryfikowanego statycznego. Podziel się swoimi przemyśleniami na temat szaleństwa IoC i Dependency Injection.
c#
java
dependency-injection
inversion-of-control
ioc-container
JP Richardson
źródło
źródło
Odpowiedzi:
Masz rację, że jeśli użyjesz kontenera jako Lokalizatora usług, będzie to mniej więcej gloryfikowana fabryka statyczna. Z wielu powodów uważam to za anty-wzór .
Jedną ze wspaniałych zalet wstrzykiwania konstruktora jest to, że łamanie zasady pojedynczej odpowiedzialności jest rażąco oczywiste.
Kiedy tak się stanie, nadszedł czas na refaktoryzację do usług fasadowych . Krótko mówiąc, utwórz nowy, bardziej gruboziarnisty interfejs, który ukrywa interakcję między niektórymi lub wszystkimi drobnoziarnistymi zależnościami, których obecnie potrzebujesz.
źródło
Nie sądzę, żeby twoi konstruktorzy klas mieli odniesienia do twojego okresu kontenera IOC. Jest to niepotrzebna zależność między klasą a kontenerem (typ zależności, jakiej IOC próbuje uniknąć!).
źródło
MyClass myClass = new MyClass(IDependency1 interface1, IDependency2 interface2)
(parametry interfejsu). Nie ma to związku z postem @ pochodnym, który interpretuję jako powiedzenie, że pojemnik do wstrzykiwania zależności nie powinien wstrzykiwać się do swoich obiektów, tj.MyClass myClass = new MyClass(this)
Trudność przekazania parametrów nie stanowi problemu. Problem polega na tym, że twoja klasa robi za dużo i powinna być bardziej rozbita.
Wstrzykiwanie zależności może działać jako wczesne ostrzeżenie dla klas, które stają się zbyt duże, szczególnie ze względu na rosnący ból przechodzenia przez wszystkie zależności.
źródło
Natknąłem się na podobne pytanie dotyczące wstrzykiwania zależności konstruktorskich i stopnia złożoności wszystkich zależności.
Jednym z podejść, które stosowałem w przeszłości, jest użycie wzoru fasady aplikacji przy użyciu warstwy usługi. To miałoby zgrubne API. Jeśli ta usługa zależy od repozytoriów, użyłaby zastrzyku ustawiającego własności prywatnych. Wymaga to utworzenia abstrakcyjnej fabryki i przeniesienia logiki tworzenia repozytoriów do fabryki.
Szczegółowy kod z wyjaśnieniem można znaleźć tutaj
Najlepsze praktyki dotyczące IoC w złożonej warstwie usług
źródło
Przeczytałem cały ten wątek dwa razy i myślę, że ludzie odpowiadają tym, co wiedzą, a nie pytaniem.
Oryginalne pytanie JP wygląda na to, że konstruuje obiekty, wysyłając resolver, a następnie kilka klas, ale zakładamy, że te klasy / obiekty same są usługami, gotowe do wstrzyknięcia. Co jeśli nie są?
JP, jeśli chcesz wykorzystać DI i pragnąć chwały mieszania zastrzyku z danymi kontekstowymi, żaden z tych wzorów (lub rzekomych „anty-wzorów”) nie rozwiązuje tego specjalnie. W rzeczywistości sprowadza się to do użycia pakietu, który wesprze Cię w takim przedsięwzięciu.
... ten format jest rzadko obsługiwany. Wierzę, że trudność programowania takiego wsparcia, dodana do nędznej wydajności, która byłaby związana z implementacją, czyni go nieatrakcyjnym dla programistów open source.
Ale należy to zrobić, ponieważ powinienem być w stanie stworzyć i zarejestrować fabrykę dla MyClass, a ta fabryka powinna być w stanie odbierać dane / dane wejściowe, które nie są popychane jako „usługa” tylko ze względu na przekazywanie dane. Jeśli „anty-wzorzec” ma negatywne konsekwencje, wówczas wymuszenie istnienia sztucznych typów usług do przekazywania danych / modeli jest z pewnością negatywne (na równi z przeczuciem, że pakujesz swoje klasy w kontener. Obowiązuje ten sam instynkt).
Istnieją ramy, które mogą pomóc, nawet jeśli wyglądają nieco brzydko. Na przykład Ninject:
Tworzenie instancji za pomocą Ninject z dodatkowymi parametrami w konstruktorze
Dotyczy to .NET, jest popularny i wciąż nie jest tak czysty, jak powinien, ale jestem pewien, że jest coś w jakimkolwiek języku, który wybierzesz.
źródło
Wstrzyknięcie pojemnika to skrót, którego ostatecznie będziesz żałować.
Nadmierne wstrzyknięcie nie stanowi problemu, jest zwykle objawem innych wad strukturalnych, w szczególności oddzielenia problemów. To nie jest jeden problem, ale może mieć wiele źródeł, a to, co czyni go tak trudnym do naprawienia, polega na tym, że będziesz musiał poradzić sobie ze wszystkimi, czasami w tym samym czasie (pomyśl o rozplątywaniu spaghetti).
Oto niepełna lista rzeczy, na które należy zwrócić uwagę
Słaby projekt domeny (agregacja katalogu głównego…. Itp.)
Niewłaściwy podział problemów (skład usługi, polecenia, zapytania) Patrz CQRS i pozyskiwanie zdarzeń.
LUB Mapujący (bądź ostrożny, te rzeczy mogą doprowadzić cię do kłopotów)
Zobacz modele i inne DTO (nigdy nie używaj ponownie jednego z nich i staraj się ograniczyć je do minimum !!!!)
źródło
Problem:
1) Konstruktor z ciągle rosnącą listą parametrów.
2) Jeśli klasa jest dziedziczona (np .:),
RepositoryBase
wówczas zmiana sygnatury konstruktora powoduje zmianę klas pochodnych.Rozwiązanie 1
Przekaż
IoC Container
do konstruktoraDlaczego
Dlaczego nie
Rozwiązanie 2
Utwórz klasę grupującą wszystkie usługi i przekaż ją konstruktorowi
Klasy pochodnej
Dlaczego
A
zależy, informacje te są gromadzoneA.Dependency
Dlaczego nie
X.Dependency
osobno)IoC Container
Rozwiązanie 2 jest jednak surowe, jeśli istnieje przeciwko temu solidny argument, doceniony zostanie komentarz opisowy
źródło
To podejście, którego używam
Oto przybliżone podejście do wykonywania wstrzyknięć i uruchamiania konstruktora po wstrzyknięciu wartości. To jest w pełni funkcjonalny program.
Obecnie pracuję nad projektem hobby, który działa tak: https://github.com/Jokine/ToolProject/tree/Core
źródło
Jakiego systemu wstrzykiwania zależności używasz? Czy zamiast tego próbowałeś zastosować zastrzyk na bazie setera?
Zaletą wstrzykiwania opartego na konstruktorach jest to, że wygląda naturalnie dla programistów Java, którzy nie używają frameworków DI. Potrzebujesz 5 rzeczy do zainicjowania klasy, a następnie masz 5 argumentów dla swojego konstruktora. Minusem jest to, co zauważyłeś, staje się niewygodne, gdy masz wiele zależności.
Za pomocą Springa możesz przekazać wymagane wartości ustawieniom i możesz użyć @required adnotacji, aby wymusić ich wstrzyknięcie. Minusem jest to, że musisz przenieść kod inicjujący z konstruktora na inną metodę i mieć wywołanie Spring, które po wstrzyknięciu wszystkich zależności poprzez oznaczenie go @PostConstruct. Nie jestem pewien co do innych frameworków, ale zakładam, że robią coś podobnego.
Oba sposoby działają, to kwestia preferencji.
źródło