Refaktoryzuję klasę i dodaję do niej nową zależność. Klasa obecnie przyjmuje swoje istniejące zależności w konstruktorze. Aby zachować spójność, dodaję parametr do konstruktora.
Oczywiście jest kilka podklas plus jeszcze więcej dla testów jednostkowych, więc teraz gram w grę polegającą na zmienianiu wszystkich konstruktorów, aby pasowały, a to trwa wieki.
To sprawia, że myślę, że używanie właściwości z ustawiającymi jest lepszym sposobem uzyskiwania zależności. Nie sądzę, aby wstrzykiwane zależności były częścią interfejsu do konstruowania instancji klasy. Dodajesz zależność i teraz wszyscy twoi użytkownicy (podklasy i każdy, kto tworzy Twoją instancję bezpośrednio) nagle o tym wiedzą. To jest jak przerwa w hermetyzacji.
Wydaje się, że nie jest to wzorzec z istniejącym tu kodem, więc chcę dowiedzieć się, jaki jest ogólny konsensus, zalety i wady konstruktorów w porównaniu z właściwościami. Czy lepsze jest używanie metod ustawiających właściwości?
źródło
Użytkownicy klasy powinni wiedzieć o zależnościach danej klasy. Gdybym miał klasę, która na przykład byłaby połączona z bazą danych i nie zapewniałaby możliwości wstrzyknięcia zależności warstwy trwałości, użytkownik nigdy nie wiedziałby, że połączenie z bazą danych musi być dostępne. Jeśli jednak zmienię konstruktora, informuję użytkowników, że istnieje zależność od warstwy trwałości.
Ponadto, aby uniknąć konieczności zmieniania każdego użycia starego konstruktora, po prostu zastosuj łańcuch konstruktorów jako tymczasowy pomost między starym i nowym konstruktorem.
Jednym z punktów wstrzykiwania zależności jest ujawnienie, jakie zależności ma klasa. Jeśli klasa ma zbyt wiele zależności, może być czas na przeprowadzenie refaktoryzacji: Czy każda metoda klasy używa wszystkich zależności? Jeśli nie, to dobry punkt wyjścia, aby zobaczyć, gdzie można podzielić klasę.
źródło
Oczywiście założenie konstruktora oznacza, że możesz zweryfikować wszystko na raz. Jeśli przypiszesz rzeczy do pól tylko do odczytu, masz pewne gwarancje dotyczące zależności obiektu od samego początku konstrukcji.
Dodawanie nowych zależności jest prawdziwym problemem, ale przynajmniej w ten sposób kompilator narzeka, dopóki nie będzie poprawny. Myślę, że to dobra rzecz.
źródło
Jeśli masz dużą liczbę opcjonalnych zależności (co już jest zapachem), prawdopodobnie najlepszym rozwiązaniem jest wstrzyknięcie setera. Wstrzyknięcie konstruktora lepiej jednak ujawnia twoje zależności.
źródło
Ogólnie preferowanym podejściem jest użycie iniekcji konstruktora tak często, jak to możliwe.
Wstrzyknięcie konstruktora dokładnie określa, jakie zależności są wymagane, aby obiekt działał poprawnie - nie ma nic bardziej irytującego niż tworzenie nowego obiektu i jego awaria podczas wywoływania metody, ponieważ nie jest ustawiona pewna zależność. Obiekt zwracany przez konstruktora powinien być w stanie roboczym.
Spróbuj mieć tylko jednego konstruktora, zachowuje prosty projekt i pozwala uniknąć niejednoznaczności (jeśli nie dla ludzi, dla kontenera DI).
Możesz użyć iniekcji właściwości, gdy masz to, co Mark Seemann nazywa lokalną wartością domyślną w swojej książce „Dependency Injection in .NET”: zależność jest opcjonalna, ponieważ możesz zapewnić dobrze działającą implementację, ale chcesz pozwolić wywołującemu na określenie innej, jeśli potrzebne.
(Poprzednia odpowiedź poniżej)
Myślę, że wtryski konstruktorów są lepsze, jeśli wtryski są obowiązkowe. Jeśli to dodaje zbyt wielu konstruktorów, rozważ użycie fabryk zamiast konstruktorów.
Nastrzykiwanie setera jest przyjemne, jeśli wtrysk jest opcjonalny lub jeśli chcesz go zmienić w połowie. Generalnie nie lubię seterów, ale to kwestia gustu.
źródło
To w dużej mierze kwestia osobistego gustu. Osobiście wolę wstrzykiwanie setera, ponieważ uważam, że zapewnia on większą elastyczność w sposobie, w jaki można zastępować implementacje w czasie wykonywania. Ponadto konstruktory z dużą ilością argumentów nie są moim zdaniem czyste, a argumenty podane w konstruktorze powinny być ograniczone do argumentów nieopcjonalnych.
Dopóki interfejs klas (API) jasno określa, czego potrzebuje do wykonania swojego zadania, jesteś dobry.
źródło
Osobiście wolę "wzorzec" wyodrębniania i przesłonięcia zamiast wstrzykiwania zależności w konstruktorze, głównie z powodu przedstawionego w pytaniu. Możesz ustawić właściwości jako,
virtual
a następnie zastąpić implementację w pochodnej testowalnej klasie.źródło
Preferuję iniekcję konstruktora, ponieważ pomaga „wymusić” wymagania dotyczące zależności klasy. Jeśli jest w c'tor, konsument musi ustawić obiekty, aby aplikacja mogła się skompilować. Jeśli używasz settera, mogą nie wiedzieć, że mają problem do czasu wykonania - iw zależności od obiektu, może to być późny czas wykonywania.
Nadal od czasu do czasu używam settera, gdy wstrzyknięty obiekt może wymagać dużo pracy, na przykład inicjalizacji.
źródło
Myślę o wtrysku konstruktora, bo wydaje się to najbardziej logiczne. To tak, jakby powiedzieć, że moja klasa wymaga tych zależności, aby wykonywać swoją pracę. Jeśli jest to zależność opcjonalna, właściwości wydają się rozsądne.
Używam również wtrysku właściwości do ustawiania rzeczy, do których kontener nie ma odniesień, takich jak widok ASP.NET na prezenterze utworzonym przy użyciu kontenera.
Nie sądzę, żeby to zrywało hermetyzację. Wewnętrzne działania powinny pozostać wewnętrzne, a zależności powinny dotyczyć innego problemu.
źródło
Jedną z opcji, którą warto rozważyć, jest tworzenie złożonych zależności wielokrotnych z prostych pojedynczych zależności. Oznacza to, że zdefiniuj dodatkowe klasy dla zależności złożonych. To sprawia, że jest trochę łatwiejsze wstrzyknięcie konstruktora WRT - mniej parametrów na wywołanie - przy jednoczesnym utrzymaniu rzeczy, która musi dostarczyć wszystkie zależności, aby utworzyć instancję.
Oczywiście ma to największy sens, jeśli istnieje jakieś logiczne grupowanie zależności, więc związek jest czymś więcej niż dowolną agregacją, a najbardziej sensowne jest, jeśli istnieje wiele zależności dla jednej zależności złożonej - ale parametr „wzorzec” bloku parametrów ma istnieją od dawna, a większość z tych, które widziałem, była dość arbitralna.
Osobiście jestem jednak bardziej fanem używania metod / ustawiania właściwości do określania zależności, opcji itp. Nazwy wywołań pomagają opisać, co się dzieje. Dobrym pomysłem jest jednak podanie przykładowych fragmentów opisujących to, jak to skonfigurować, i upewnić się, że klasa zależna wykonuje wystarczającą liczbę sprawdzeń błędów. Do konfiguracji warto użyć modelu skończonego stanu.
źródło
Niedawno natknąłem się na sytuację, w której miałem wiele zależności w klasie, ale tylko jedna z zależności musiała się zmieniać w każdej implementacji. Ponieważ zależności dostępu do danych i rejestrowania błędów prawdopodobnie zostałyby zmienione tylko w celach testowych, dodałem opcjonalne parametry dla tych zależności i zapewniłem domyślne implementacje tych zależności w moim kodzie konstruktora. W ten sposób klasa zachowuje swoje domyślne zachowanie, chyba że zostanie nadpisane przez konsumenta klasy.
Używanie parametrów opcjonalnych można osiągnąć tylko w platformach, które je obsługują, takich jak .NET 4 (zarówno dla C #, jak i VB.NET, chociaż VB.NET zawsze je miał). Oczywiście, możesz osiągnąć podobną funkcjonalność, po prostu używając właściwości, która może zostać ponownie przypisana przez konsumenta twojej klasy, ale nie uzyskasz korzyści z niezmienności zapewnianej przez przypisanie obiektu prywatnego interfejsu do parametru konstruktora.
Biorąc to wszystko pod uwagę, jeśli wprowadzasz nową zależność, która musi być dostarczona przez każdego konsumenta, będziesz musiał zrefaktoryzować swój konstruktor i cały kod konsumujący twoją klasę. Moje sugestie powyżej naprawdę mają zastosowanie tylko wtedy, gdy masz luksus możliwości zapewnienia domyślnej implementacji dla całego twojego obecnego kodu, ale nadal zapewniasz możliwość zastąpienia domyślnej implementacji, jeśli to konieczne.
źródło
To jest stary post, ale jeśli będzie potrzebny w przyszłości, może się przydać:
https://github.com/omegamit6zeichen/prinject
Miałem podobny pomysł i wymyśliłem ten framework. Prawdopodobnie jest daleki od ukończenia, ale jest to idea frameworka skupiającego się na wstrzykiwaniu właściwości
źródło
To zależy od tego, jak chcesz wdrożyć. Wolę wstrzykiwanie konstruktora wszędzie tam, gdzie czuję, że wartości, które wchodzą do implementacji, nie zmieniają się często. Np .: Jeśli strategia firmy jest zgodna z serwerem Oracle, skonfiguruję wartości źródła danych dla połączeń osiągających bean za pośrednictwem iniekcji konstruktora. W przeciwnym razie, jeśli moja aplikacja jest produktem i jest szansa, że może połączyć się z dowolną bazą danych klienta, zaimplementowałbym taką konfigurację bazy danych i implementację wielu marek poprzez wstrzyknięcie setera. Właśnie wziąłem przykład, ale są lepsze sposoby realizacji scenariuszy, o których wspomniałem powyżej.
źródło
Wstrzyknięcie konstruktora jawnie ujawnia zależności, dzięki czemu kod jest bardziej czytelny i mniej podatny na nieobsłużone błędy czasu wykonywania, jeśli argumenty są sprawdzane w konstruktorze, ale tak naprawdę sprowadza się to do osobistej opinii, a im więcej używasz DI, tym więcej będziesz mają tendencję do kołysania się w jedną lub drugą stronę, w zależności od projektu. Osobiście mam problemy z kodem, który pachnie jak konstruktory z długą listą argumentów i uważam, że konsument obiektu powinien znać zależności, aby mimo to użyć obiektu, więc jest to argument za użyciem wstrzykiwania właściwości. Nie podoba mi się niejawny charakter wstrzykiwania właściwości, ale uważam, że jest on bardziej elegancki, co skutkuje bardziej przejrzystym kodem. Z drugiej strony iniekcja konstruktora zapewnia wyższy stopień hermetyzacji,
Wybierz zastrzyk według konstruktora lub według właściwości mądrze w oparciu o konkretny scenariusz. I nie myśl, że musisz używać DI tylko dlatego, że wydaje się to konieczne i zapobiegnie to niewłaściwemu projektowi i zapachowi kodu. Czasami użycie wzoru nie jest warte wysiłku, jeśli wysiłek i złożoność przewyższają korzyści. Nie komplikuj.
źródło