Wstrzykiwanie zależności a wzorzec fabryczny


498

Większość przytoczonych przykładów użycia wstrzykiwania zależności możemy rozwiązać również przy użyciu wzorca fabrycznego. Wygląda na to, że jeśli chodzi o użycie / projektowanie, różnica między wtryskiem zależności a fabryką jest rozmyta lub cienka.

Kiedyś ktoś mi powiedział, że to, jak go używasz, robi różnicę!

Kiedyś użyłem StructureMap do kontenera DI, aby rozwiązać problem, później przeprojektowałem go do pracy z prostą fabryką i usunąłem odniesienia do StructureMap.

Czy ktoś może mi powiedzieć, jaka jest między nimi różnica i gdzie z czego korzystać, jaka jest najlepsza praktyka tutaj?


21
Czy te dwa podejścia nie mogą się wzajemnie uzupełniać: stosowanie wstrzykiwania zależności do wstrzykiwania klas fabrycznych?
Richard Ev

20
Byłoby naprawdę miło, gdyby to pytanie zawierało odpowiedź z jakimś kodem! Nadal nie rozumiem, w jaki sposób DI byłby korzystny / różny od używania fabryki do tworzenia? Musisz tylko wymienić ten jeden wiersz w klasie fabrycznej, aby zmienić, który obiekt / implementacja jest tworzona?
gideon

2
@gideon nie zmusiłoby cię to do skompilowania aplikacji, a przynajmniej modułu zawierającego klasę fabryczną?
kwas lizergowy

1
@liortal tak, właśnie tak. Przeprowadziłem długie badania nad DI od tego komentarza i teraz rozumiem, że DI wyprzedza metodę fabryczną.
gideon

1
Sprawdź tę świetną odpowiedź: stackoverflow.com/questions/4985455/… - bardzo dobrze wypowiada się i dostarcza próbki kodu.
Luis Perez

Odpowiedzi:


293

Podczas korzystania z fabryki Twój kod jest nadal odpowiedzialny za tworzenie obiektów. Poprzez DI przekazujesz tę odpowiedzialność innej klasie lub platformie, która jest niezależna od twojego kodu.


172
Wzorzec DI nie wymaga żadnych ram. Możesz zrobić DI, ręcznie pisząc fabryki, które wykonują DI. Ramy DI po prostu to ułatwiają.
Esko Luontola

28
@Perpetualcoder - Dzięki @Esko - Nie daj się wciągnąć w strukturę słów oznaczającą zaawansowaną bibliotekę innej firmy.
willcodejavaforfood

4
+1 dzięki kodowi dzięki! Więc musisz zmienić pliki config / xml. Widzę. Link wiki pl.wikipedia.org/wiki/… definiuje wzór fabryczny jakoManually-Injected Dependency
gideon

5
Nie mam przewagi, że zmieniam 1 linię XML w porównaniu do zmiany 1 linii kodu. Czy mógłbyś opracować?
Rafael Eyng

1
Powtórz odpowiedź OP, zastępując „DI” słowem „fabryka”, nadal ma sens.
Edson Medina,

219

Sugerowałbym, aby koncepcje były jasne i proste. Dependency Injection jest bardziej architektonicznym wzorem do luźnego łączenia komponentów oprogramowania. Wzorzec fabryczny to tylko jeden ze sposobów rozdzielenia odpowiedzialności za tworzenie obiektów innych klas na inny byt. Wzorzec fabryczny można wywołać jako narzędzie do implementacji DI. Wstrzykiwanie zależności można wdrożyć na wiele sposobów, takich jak DI przy użyciu konstruktorów, mapowania plików xml itp.


4
To prawda, że ​​Factory Pattern jest jednym ze sposobów implementacji wstrzykiwania zależności. Kolejną korzyścią wynikającą z zastosowania wstrzykiwania zależności od wzorca fabrycznego jest to, że frameworki DI dają elastyczność w rejestrowaniu abstrakcji względem konkretnych typów. Takich jak Code, Config, XML lub Auto Configuration. Ta elastyczność pozwoli ci zarządzać czasem życia twoich obiektów lub zdecydować, jak i kiedy zarejestrować swoje interfejsy.
Teoman shipahi

1
Wzorzec fabryczny oferuje abstrakcję wyższego poziomu niż DI. Fabryka może oferować opcje konfiguracji tak samo jak DI, ale może również ukryć wszystkie szczegóły konfiguracji, aby fabryka mogła zdecydować się na zupełnie inną implementację bez wiedzy klienta. Sam DI nie pozwala na to. DI wymaga od klienta określenia żądanych zmian.
neuron

1
Niezła odpowiedź. Wielu myli się z tym pytaniem: „Jakie wzory powinienem wybrać?” W rzeczywistości wzorce projektowe są tylko sposobem na rozwiązanie problemu w odpowiednich sytuacjach. Jeśli nie wiesz, jakiego wzoru należy użyć lub „Gdzie powinienem zaimplementować wzór?” to nie potrzebujesz tego w tej chwili.
Benyi

2
Myślę, że dokładniej jest powiedzieć, że Factory Pattern to narzędzie do implementacji IoC (nie DI). Należy pamiętać, że DI jest formą IoC
Hooman Bahreini

185

Wstrzykiwanie zależności

Zamiast tworzyć same części, samochód pyta o części, które musi funkcjonować.

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

Fabryka

Składa elementy razem, aby stworzyć kompletny obiekt i ukrywa konkretny typ przed dzwoniącym.

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

Wynik

Jak widać, fabryki i DI wzajemnie się uzupełniają.

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

Czy pamiętasz złotowłosa i trzy niedźwiedzie? Cóż, zastrzyk zależności jest w pewnym sensie taki. Oto trzy sposoby na zrobienie tego samego.

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

Przykład # 1 - Jest to najgorsze, ponieważ całkowicie ukrywa zależność. Jeśli spojrzałeś na tę metodę jako na czarną skrzynkę, nie miałbyś pojęcia, że ​​wymaga samochodu.

Przykład 2 - To jest trochę lepsze, ponieważ teraz wiemy, że potrzebujemy samochodu, ponieważ mijamy w fabryce samochodów. Ale tym razem mijamy za dużo, ponieważ cała metoda faktycznie potrzebuje samochodu. Mijamy fabrykę tylko po to, żeby zbudować samochód, kiedy samochód mógłby być zbudowany poza metodą i przekazany.

Przykład 3 - Jest to idealne rozwiązanie, ponieważ metoda pyta o dokładnie to , czego potrzebuje. Nie za dużo lub za mało. Nie muszę pisać MockCarFactory tylko po to, aby stworzyć MockCars, mogę przekazać próbkę bezpośrednio. Jest to bezpośrednie i interfejs nie kłamie.

Ten Google Talk Talk Misko Hevery jest niesamowity i jest podstawą tego, z czego zaczerpnąłem mój przykład. http://www.youtube.com/watch?v=XcT4yYu_TTs


1
Wzór fabryczny jest wstrzykiwany jako DI.
Mangesh Pimpalkar

7
@PhilGoetz To, co opisujesz, bardziej przypomina wzorzec lokalizatora usług. Mają podobne cele, polegające na oddzieleniu usług od konsumentów. Istnieje jednak wiele wad wzorca Service Locator. Głównie ukrywanie zależności nie jest dobrą rzeczą. Konsument nadal musi uzyskać swoje zależności, ale zamiast definiować przejrzysty interfejs, są one przekazywane „potajemnie” i polegają na stanie globalnym. W tym przykładzie konsument nie ma pojęcia o fabryce, tylko pyta o to, czego potrzebuje i nie musi się martwić o to, jak zbudowana jest ta potrzeba.
Despertar

1
@MatthewWhited Większość decyzji projektowych wymaga kompromisu. Dzięki DI zyskujesz elastyczność, przejrzystość i bardziej testowalny system, ale kosztem ujawnienia swoich wnętrzności. Wiele osób uważa to za akceptowalny kompromis. Nie oznacza to, że DI jest zawsze najlepszym rozwiązaniem i to pytanie nie dotyczy tego. Ten przykład ma pokazać różnicę między wzorcem DI a wzorcem fabrycznym, pokazując niektóre dobre i złe zastosowania każdego z nich.
Despertar,

3
To nie jest wzorzec DI, to tylko implementacja IoC. DI używa ServiceLocator w celu ustalenia właściwej zależności i wstrzyknięcia jej do konstruktora podczas tworzenia obiektu, twój kod jedynie segreguje tworzenie obiektów od zakresu twojej klasy.
Diego Mendes,

3
@DiegoMendes To, co opisujesz, to środowisko automatyzujące DI. ServiceLocator, jak go nazywasz, wykonuje DI dla Ciebie. To, co pokazuję, to sam wzór, który nie wymaga żadnych fantazyjnych ram. Zobacz stackoverflow.com/a/140655/1160036 lub zobacz en.wikipedia.org/wiki/… : „[lista frameworków] obsługuje wstrzykiwanie zależności, ale nie jest wymagane do wstrzykiwania zależności”. Ponadto „Wstrzyknięcie to przekazanie zależności do obiektu zależnego”. Nadmiernie komplikujesz pięknie prostą koncepcję.
Despertar

50

Powód wstrzykiwania zależności (DI) i wzorców fabrycznych jest podobny, ponieważ są to dwie implementacje Inversion of Control (IoC), która jest architekturą oprogramowania. Mówiąc wprost, są to dwa rozwiązania tego samego problemu.

Aby odpowiedzieć na pytanie, główną różnicą między wzorcem fabrycznym a DI jest sposób uzyskiwania odniesienia do obiektu. Z iniekcją zależności, jak sama nazwa wskazuje, wstrzyknięto odwołanie lub podano kod. W przypadku wzorca fabrycznego kod musi żądać odwołania, aby kod pobierał obiekt. Obie implementacje usuwają lub rozłączają powiązanie między kodem a bazową klasą lub typem odwołania do obiektu używanego przez kod.

Warto zauważyć, że wzorce fabryczne (a nawet abstrakcyjne wzorce fabryczne, które są fabrykami, które zwracają nowe fabryki, które zwracają odwołania do obiektów), mogą być zapisywane w celu dynamicznego wyboru lub połączenia z typem lub klasą obiektu żądanego w czasie wykonywania. To czyni je bardzo podobnymi (nawet bardziej niż DI) do wzorca Service Locator, który jest kolejną implementacją IoC.

Wzorzec projektowania fabryki jest dość stary (pod względem oprogramowania) i istnieje już od jakiegoś czasu. Od niedawnej popularności wzoru architektonicznego IoC odradza się.

Myślę, że jeśli chodzi o wzorce projektowania IoC: wtryskiwacze wstrzykują, lokalizatory lokalizują, a fabryki zostały zrefaktoryzowane.


3
To najlepsza odpowiedź ... inne odpowiedzi albo nie wspominają o IoC, albo nie rozpoznają, że DI jest formą IoC.
Hooman Bahreini

Dzięki, kiedy po raz pierwszy studiowałem MKOl, prawie krzyczałem, że to tylko kolejna forma fabrycznego wzorca, okazuje się, że są naprawdę do siebie podobni
Harvey Lin

40

Istnieją problemy, które można łatwo rozwiązać za pomocą wstrzykiwania zależności, których nie da się tak łatwo rozwiązać za pomocą zestawu fabryk.

Niektóre różnice między z jednej strony inwersją kontroli i iniekcją zależności (IOC / DI), a z drugiej strony lokalizatorem usług lub pakietem fabryk (fabryka), to:

IOC / DI to kompletny ekosystem obiektów i usług domenowych sam w sobie. Ustawia wszystko dla ciebie w określony sposób. Obiekty i usługi domeny są konstruowane przez kontener i nie konstruują się same: dlatego nie mają żadnych zależności od kontenera ani żadnych fabryk. IOC / DI pozwala na bardzo wysoki stopień konfigurowalności, przy czym cała konfiguracja znajduje się w jednym miejscu (konstrukcja kontenera) w najwyższej warstwie aplikacji (GUI, interfejs WWW).

Factory streszcza niektóre elementy konstrukcji i usług domeny. Ale obiekty i usługi domenowe są nadal odpowiedzialne za wymyślenie, jak się konstruować i jak zdobyć wszystkie rzeczy, na których polegają. Wszystkie te „aktywne” zależności są filtrowane przez wszystkie warstwy aplikacji. Nie ma jednego miejsca do skonfigurowania wszystkiego.


26

Jedną wadą DI jest to, że nie może on inicjować obiektów logiką. Na przykład, kiedy muszę utworzyć postać o losowej nazwie i wieku, DI nie jest wyborem w stosunku do wzorca fabrycznego. Dzięki fabrykom możemy łatwo kapsułkować losowy algorytm z tworzenia obiektów, który obsługuje jeden z wzorców projektowych o nazwie „Hermetyzuj to, co się zmienia”.


22

Zarządzanie cyklem życia jest jednym z zadań, które oprócz instancji i iniekcji przyjmują również pojemniki zależności. Fakt, że kontener czasami zawiera odniesienie do komponentów po utworzeniu wystąpienia, jest powodem, dla którego nazywany jest „kontenerem”, a nie fabryką. Pojemniki do wstrzykiwania zależności zwykle przechowują tylko odniesienia do obiektów, których potrzebuje do zarządzania cyklami życia, lub które są ponownie wykorzystywane do przyszłych zastrzyków, takich jak singletony lub ciężary latające. Po skonfigurowaniu do tworzenia nowych wystąpień niektórych składników dla każdego wywołania kontenera kontener zwykle zapomina o utworzonym obiekcie.

Od: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html


15

Uważam, że DI jest rodzajem warstwy abstrakcji w fabrykach, ale zapewniają one również korzyści wykraczające poza abstrakcję. Prawdziwa fabryka wie, jak utworzyć pojedynczy typ i skonfigurować go. Dobra warstwa DI zapewnia, poprzez konfigurację, tworzenie i konfigurowanie wielu typów.

Oczywiście w przypadku projektu z kilkoma prostymi typami, które wymagają stosunkowo stabilnej logiki biznesowej w ich konstrukcji, wzór fabryczny jest prosty do zrozumienia, wdrożenia i działa dobrze.

OTOH, jeśli masz projekt zawierający wiele typów, których implementacje oczekujesz często zmieniać, DI daje ci elastyczność dzięki swojej konfiguracji, aby wykonywać to w czasie wykonywania bez konieczności ponownej kompilacji fabryk.


14

Teoria

Należy wziąć pod uwagę dwa ważne punkty:

  1. Kto tworzy przedmioty

    • [Fabrycznie]: Musisz napisać, w jaki sposób należy utworzyć obiekt. Masz osobną klasę Factory, która zawiera logikę tworzenia.
    • [Dependency Injection]: W praktycznych przypadkach są wykonywane przez zewnętrzne frameworki (na przykład w Javie, które byłoby wiosenne / ejb / guice). Wtrysk odbywa się „magicznie” bez wyraźnego tworzenia nowych obiektów
  2. Jakimi obiektami zarządza:

    • [Fabrycznie]: zazwyczaj odpowiedzialny za tworzenie obiektów stanowych
    • [Zastrzyki zależności] Bardziej prawdopodobne jest tworzenie obiektów bezstanowych

Praktyczny przykład wykorzystania zastrzyku zarówno fabrycznego, jak i zależnościowego w jednym projekcie

  1. Co chcemy zbudować

Moduł aplikacji do tworzenia zamówienia, który zawiera wiele wpisów o nazwie linia zamówienia.

  1. Architektura

Załóżmy, że chcemy stworzyć następującą architekturę warstw:

wprowadź opis zdjęcia tutaj

Obiektami domenowymi mogą być obiekty przechowywane w bazie danych. Repozytorium (DAO) pomaga w pobieraniu obiektów z bazy danych. Usługa zapewnia API dla innych modułów. Pozwala na operacje na ordermodule

  1. Warstwa domen i wykorzystanie fabryk

Podmioty, które będą w bazie danych to Order i OrderLine. Zamówienie może mieć wiele linii zamówień. Związek między zamówieniem a zamówieniem

Teraz przychodzi ważna część projektu. Czy moduły poza tym powinny tworzyć i zarządzać OrderLines we własnym zakresie? Nie. Linia zamówienia powinna istnieć tylko wtedy, gdy masz z nią powiązane zamówienie. Byłoby najlepiej, gdybyś mógł ukryć wewnętrzne wdrożenie dla klas zewnętrznych.

Ale jak stworzyć Zamówienie bez wiedzy o OrderLines?

Fabryka

Ktoś, kto chce utworzyć nowe zamówienie, użył OrderFactory (co ukryje szczegóły dotyczące tego, jak tworzymy zamówienie).

wprowadź opis zdjęcia tutaj

Tak to będzie wyglądać w IDE. Klasy poza domainpakietem będą używane OrderFactoryzamiast konstruktora wewnątrzOrder

  1. Wstrzykiwanie zależności Wstrzykiwanie zależności jest częściej stosowane w przypadku warstw bezstanowych, takich jak repozytorium i usługa.

OrderRepository i OrderService są zarządzane przez strukturę wstrzykiwania zależności. Repozytorium odpowiada za zarządzanie operacjami CRUD w bazie danych. Usługa wstrzykuje repozytorium i używa go do zapisywania / znajdowania poprawnych klas domen.

wprowadź opis zdjęcia tutaj


Czy możesz to wyjaśnić? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsNie rozumiem dlaczego
Maksim Dmitriev

2
Obiekty stanowe prawdopodobnie znajdują się w warstwie domenowej aplikacji, w której mapujesz dane do bazy danych, zwykle tam nie używasz wstrzykiwania zależności. Fabryka jest często używana do tworzenia agregatuRoot z drzewa skomplikowanych obiektów
Marcin Szymczak

12

Wiem, że to pytanie jest stare, ale chciałbym dodać moje pięć centów,

Myślę, że wstrzykiwanie zależności (DI) jest pod wieloma względami konfigurowalnym wzorcem fabrycznym (FP) iw tym sensie wszystko, co można zrobić z DI, będzie w stanie zrobić z taką fabryką.

W rzeczywistości, jeśli na przykład używasz sprężyny, masz opcję automatycznego zasilania (DI) lub robienia czegoś takiego:

MyBean mb = ctx.getBean("myBean");

A następnie użyj tego wystąpienia „mb”, aby cokolwiek zrobić. Czy to nie jest wezwanie do fabryki, która zwróci ci instancję?

Jedyną prawdziwą różnicą, którą zauważam między większością przykładów FP, jest to, że możesz skonfigurować, co „myBean” znajduje się w xml lub w innej klasie, a framework będzie działał jak fabryka, ale poza tym jest to to samo, a ty może mieć z pewnością Fabrykę, która czyta plik konfiguracyjny lub pobiera implementację zgodnie z potrzebami.

A jeśli zapytasz mnie o moją opinię (i wiem, że nie), wierzę, że DI robi to samo, ale tylko zwiększa złożoność rozwoju, dlaczego?

Cóż, po pierwsze, aby wiedzieć, jaka implementacja jest używana dla dowolnego komponentu bean, którego używasz automatycznie w DI, musisz przejść do samej konfiguracji.

ale ... co z obietnicą, że nie będziesz musiał znać implementacji obiektu, którego używasz? pfft! poważnie? kiedy zastosujesz takie podejście ... czy nie jesteś tym samym, który pisze implementację? a nawet jeśli nie, to czy nie prawie cały czas patrzysz, jak implementacja robi to, co powinna?

i na koniec, nie ma znaczenia, ile framework DI obiecuje ci, że będziesz budował rzeczy od niego niezwiązane , bez zależności od ich klas, jeśli używasz frameworka, budujesz wszystko na nim, jeśli musisz zmień podejście lub ramy, to nie będzie łatwe zadanie ... KIEDYKOLWIEK! ... ale ponieważ budujesz wszystko wokół tego konkretnego środowiska, zamiast martwić się o najlepsze rozwiązanie dla Twojej firmy, staniesz przed poważnym problemem.

W rzeczywistości jedyną prawdziwą aplikacją biznesową dla podejścia FP lub DI, którą widzę, jest konieczność zmiany implementacji używanych w środowisku wykonawczym , ale przynajmniej znane mi ramy nie pozwalają na to, musisz odejść wszystko idealne w konfiguracji w czasie programowania i jeśli potrzebujesz, użyj innego podejścia.

Tak więc, jeśli mam klasę, która działa w różny sposób w dwóch zakresach w tej samej aplikacji (powiedzmy, dwie firmy holdingu), muszę skonfigurować strukturę, aby utworzyć dwie różne komponenty i dostosować mój kod, aby z nich korzystać. Czy to nie to samo, gdybym napisał coś takiego:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

tak samo jak to:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

I to:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

W każdym razie będziesz musiał coś zmienić w swojej aplikacji, czy to w klasach, czy w plikach konfiguracyjnych, ale musisz to zrobić ponownie.

Czy nie byłoby miło zrobić coś takiego:

MyBean mb = (MyBean)MyFactory.get("mb"); 

I w ten sposób ustawiasz kod fabryki, aby uzyskać właściwą implementację w czasie wykonywania w zależności od zalogowanego przedsiębiorstwa użytkownika? Teraz to byłoby pomocne. Możesz po prostu dodać nowy jar z nowymi klasami i ustawić reguły, może nawet w czasie wykonywania (lub dodać nowy plik konfiguracyjny, jeśli pozostawisz tę opcję otwartą), bez zmian w istniejących klasach. To byłaby fabryka dynamiczna!

czy nie byłoby to bardziej pomocne niż konieczność napisania dwóch konfiguracji dla każdego przedsiębiorstwa, a może nawet posiadania dwóch różnych aplikacji dla każdego?

Możesz mi powiedzieć, że nie muszę nigdy zmieniać przełącznika w czasie wykonywania, więc konfiguruję aplikację, a jeśli odziedziczę klasę lub użyję innej implementacji, po prostu zmieniam konfigurację i wdrożyłem ponownie. Ok, można to również zrobić w fabryce. I szczerze mówiąc, ile razy to robisz? może tylko wtedy, gdy masz aplikację, która będzie używana gdzie indziej w Twojej firmie, i przekażesz kod innemu zespołowi, a oni zrobią takie rzeczy. Ale hej, można to również zrobić w fabryce, a byłoby jeszcze lepiej w dynamicznej fabryce !!

W każdym razie sekcja komentarzy, jeśli jesteś otwarta, aby mnie zabić.


3
Zbyt wielu programistów uważa, że ​​frameworki Dependency Injection są tworzone w celu wprowadzenia czegoś nowego. Jak dobrze wyjaśnisz, tradycyjne fabryki (najczęściej fabryki abstrakcyjne) mogą odgrywać tę samą rolę, co odwracanie zależności. Inwersja czy wtrysk? Dla mnie jedyną „zaletą” frameworku Dependency Injection jest to, że nie musimy zmieniać / rekompilować kodu (ponieważ najczęściej konfigurowalny z XML-em jak Spring), gdy zależność jest dodawana / zmieniana. Po co unikać ponownej kompilacji? Aby uniknąć potencjalnych błędów ludzkich przy zmianie zależności / fabryki. Ale z naszymi świetnymi IDE refaktoryzacja gra dobrze :)
Mik378

6

MKOl to koncepcja realizowana na dwa sposoby. Tworzenie zależności i wstrzykiwanie zależności, fabryka / fabryka abstrakcyjna są przykładem tworzenia zależności. Wstrzykiwanie zależności jest konstruktorem, ustawiaczem i interfejsem. Rdzeń MKOl nie polega na konkretnych klasach, ale definiuje abstrakt metod (powiedzmy klasę interfejsu / klasy abstrakcyjnej) i używa tego abstraktu do wywoływania metody konkretnej klasy. Podobnie jak wzorzec fabryczny zwraca klasę bazową lub interfejs. Podobnie wstrzykiwanie zależności wykorzystuje klasę bazową / interfejs do ustawiania wartości dla obiektów.


4

Dzięki wstrzykiwaniu zależności klient nie musi samodzielnie uzyskiwać swoich zależności, wszystko jest wcześniej przygotowane.

W przypadku fabryk ktoś musi do nich zadzwonić, aby przenieść wygenerowane obiekty do miejsca, w którym są potrzebne.

Różnica polega głównie na tej jednej linii, w której odbywa się wywoływanie fabryki i pobieranie skonstruowanego obiektu.

Ale w fabrykach musisz napisać 1 linię wszędzie tam, gdzie potrzebujesz takiego obiektu. Z DI musisz tylko raz stworzyć okablowanie (relację między użytkowaniem a stworzonym obiektem) i po prostu polegać na obecności obiektu później. Z drugiej strony DI często wymaga nieco więcej (ile zależy od frameworka) pracy po stronie przygotowawczej.


3

Miałem to samo pytanie, gdy tylko przeczytałem o DI i znalazłem się w tym poście. Więc w końcu to zrozumiałem, ale proszę, popraw mnie, jeśli się mylę.

„Dawno temu istniały małe królestwa z własnymi organami zarządzającymi kontrolującymi i podejmującymi decyzje na podstawie własnych pisemnych zasad. Później utworzono duży rząd eliminujący wszystkie te małe organy zarządzające, które mają jeden zestaw zasad (konstytucji) i są wdrażane przez sądy”

Organami zarządzającymi małych królestw są „fabryki”

Duży rząd to „Dependency Injector”.


1
KIEDY więc ktoś uważa, że ​​poprzedni mały rząd jest teraz duży? Jakim środkiem?
Więzień ZERO

3

Możesz rzucić okiem na ten link, aby porównać dwa (i inne) podejścia w prawdziwym przykładzie.

Zasadniczo, gdy zmieniają się wymagania, modyfikujesz więcej kodu, jeśli używasz fabryk zamiast DI.

Dotyczy to również ręcznego DI (tzn. Gdy nie ma zewnętrznego frameworka, który zapewnia zależności dla twoich obiektów, ale przekazujesz je w każdym konstruktorze).


3

Większość odpowiedzi tutaj wyjaśnia różnice koncepcyjne i szczegóły implementacji obu. Nie udało mi się jednak znaleźć wyjaśnienia na temat różnicy w aplikacji, która IMO jest najważniejsza i o którą zapytał PO. Pozwól mi więc ponownie otworzyć ten temat ...

Kiedyś ktoś mi powiedział, że to, jak go używasz, robi różnicę!

Dokładnie. W 90% przypadków można uzyskać odniesienie do obiektu za pomocą Factory lub DI i zwykle kończy się to drugim. W kolejnych 10% przypadków użycie Fabryki jest tylko poprawnym sposobem . Przypadki te obejmują uzyskiwanie obiektów przez zmienną przy parametrach środowiska wykonawczego. Lubię to:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

W takim przypadku uzyskanie clientod DI nie jest możliwe (lub przynajmniej wymaga trochę brzydkiego obejścia). Zatem ogólną zasadą jest podejmowanie decyzji: jeśli można uzyskać zależność bez parametrów obliczonych w czasie wykonywania, wówczas preferowane jest DI, w przeciwnym razie należy użyć Fabrycznie.


2

wierzę, że DI to sposób konfiguracji lub tworzenia instancji fasoli. DI można wykonać na wiele sposobów, takich jak konstruktor, setter-getter itp.

Wzór fabryczny to tylko kolejny sposób tworzenia instancji fasoli. ten wzorzec będzie używany głównie, gdy trzeba tworzyć obiekty przy użyciu fabrycznego wzorca projektowego, ponieważ podczas używania tego wzorca nie konfigurujesz właściwości fasoli, tylko tworzysz obiekt.

Sprawdź ten link: Wstrzykiwanie zależności


2

Binoj,

Nie sądzę, że musisz wybierać między sobą.

Przeniesienie zależnej klasy lub interfejsu do konstruktora lub ustawiacza klasy odbywa się według wzorca DI. Obiekt przekazywany do konstruktora lub zestawu można zaimplementować w programie Factory.

Kiedy użyć? Użyj wzoru lub wzorów, które znajdują się w sterówce programisty. W czym czują się najbardziej komfortowo i są najłatwiejsze do zrozumienia.


2

Uważam, że 3 ważne aspekty rządzą obiektami i ich wykorzystaniem:
1. Tworzenie instancji (klasy wraz z ewentualną inicjalizacją).
2. Zastrzyk (tak utworzonej instancji) tam, gdzie jest wymagany.
3. Zarządzanie cyklem życia (tak utworzonej instancji).

Przy użyciu wzorca fabrycznego osiąga się pierwszy aspekt (tworzenie instancji), ale pozostałe dwa są wątpliwe. Klasa korzystająca z innych instancji musi zakodować na stałe fabryki (zamiast tworzenia instancji), co utrudnia utratę zdolności łączenia. Ponadto zarządzanie cyklem życiainstancji staje się wyzwaniem w dużej aplikacji, w której fabryka jest używana w wielu miejscach (szczególnie jeśli fabryka nie zarządza cyklem życia instancji, którą zwraca, robi się brzydka).

Z drugiej strony, używając DI (wzorca IoC), wszystkie 3 są wyodrębniane poza kodem (do kontenera DI), a zarządzana fasola nie potrzebuje niczego o tej złożoności. Luźne połączenie , bardzo ważny cel architektoniczny można osiągnąć cicho i wygodnie. Kolejny ważny cel architektoniczny, rozdzielenie problemów można osiągnąć znacznie lepiej niż fabryki.

Podczas gdy fabryki mogą być odpowiednie do małych zastosowań, duże lepiej byłoby wybrać DI niż fabryki.


1

Moje myśli:

Dependecy Injection: przekazuj współpracowników jako parametry do konstruktorów. Dependency Injection Framework: ogólna i konfigurowalna fabryka do tworzenia obiektów, które będą przekazywane jako parametry do konstruktorów.


1
Tak, dokładnie. Prawie wszystkie wzmianki o wstrzykiwaniu zależności (DI) w niniejszym pytaniu i pytaniu niewłaściwie używają tego terminu w przeciwieństwie do tej definicji. Dependency Injection Container (DIC) jest najczęstszym szkieletem działającym jako ogólna i konfigurowalna fabryka do tworzenia obiektów.
CXJ

1

Struktura wtrysku jest implementacją Wzorca Fabrycznego.

Wszystko zależy od twoich wymagań. Jeśli musisz zaimplementować wzorzec fabryczny w aplikacji, jest bardzo prawdopodobne, że twoje wymagania zostaną spełnione przez jedną z niezliczonych implementacji frameworku.

Powinieneś wdrożyć własne rozwiązanie tylko wtedy, gdy twoje wymagania nie mogą być spełnione przez żaden z zewnętrznych frameworków. Im więcej kodu piszesz, tym więcej kodu musisz zachować. Kod jest zobowiązaniem, a nie aktywem.

Argumenty, które implementacje powinieneś zastosować, nie są tak fundamentalnie ważne, jak zrozumienie architektonicznych potrzeb Twojej aplikacji.


1

Wzorzec projektowania fabryki

Wzór fabryczny charakteryzuje się

  • Interfejs
  • Klasy implementacyjne
  • Fabryka

Możesz zaobserwować kilka rzeczy, gdy zadajesz sobie pytanie, jak poniżej

  • Kiedy fabryka utworzy obiekt dla klas implementacji - czas działania czy czas kompilacji?
  • Co jeśli chcesz zmienić implementację w czasie wykonywania? - Niemożliwe

Są one obsługiwane przez wstrzyknięcie zależności.

Zastrzyk zależności

Możesz mieć różne sposoby wstrzykiwania zależności. Dla uproszczenia puszczamy interfejs wtrysku

W DI kontener tworzy potrzebne instancje i „wstrzykuje” je do obiektu.

W ten sposób eliminuje instancję statyczną.

Przykład:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

Z wartości nominalnej wyglądają tak samo

Mówiąc najprościej, Factory Pattern, Creational Pattern pomaga stworzyć nam obiekt - „Zdefiniuj interfejs do tworzenia obiektu”. Jeśli mamy rodzaj puli obiektów o wartości kluczowej (np. Słownik), przekazując klucz do fabryki (mam na myśli prosty wzorzec fabryczny), można rozwiązać typ. Zadanie wykonane! Z drugiej strony wydaje się, że to samo robi Dependency Injection Framework (takie jak Structure Map, Ninject, Unity ... itd.).

Ale ... „Nie wymyślaj koła ponownie”

Z architektonicznego punktu widzenia jest to warstwa wiążąca i „Nie wymyślaj koła ponownie”.

W przypadku aplikacji klasy korporacyjnej koncepcja DI jest bardziej warstwą architektoniczną, która określa zależności. Aby jeszcze bardziej to uprościć, możesz myśleć o tym jako o osobnym projekcie biblioteki klasowej, który rozwiązuje zależności. Główna aplikacja zależy od tego projektu, w którym moduł rozpoznawania zależności odnosi się do innych konkretnych implementacji i rozwiązywania zależności.

Oprócz „GetType / Create” z fabryki, najczęściej potrzebujemy więcej funkcji (możliwość używania XML do definiowania zależności, kpiny i testowania jednostek itp.). Ponieważ odwoływałeś się do mapy struktury, spójrz na listę funkcji mapy struktury . Jest to wyraźnie coś więcej niż rozwiązywanie prostych mapowań obiektów. Nie wymyślaj koła na nowo!

Jeśli masz tylko młotek, wszystko wygląda jak gwóźdź

W zależności od wymagań i rodzaju tworzonej aplikacji musisz dokonać wyboru. Jeśli ma tylko kilka projektów (może to być jeden lub dwa ..) i wiąże się z niewielkimi zależnościami, możesz wybrać prostsze podejście. To jak korzystanie z dostępu do danych ADO .Net w porównaniu z używaniem Entity Framework do prostych 1 lub 2 wywołań bazy danych, gdzie wprowadzenie EF jest przesadą w tym scenariuszu.

Ale w przypadku większego projektu lub jeśli projekt staje się większy, zdecydowanie polecam mieć warstwę DI z ramą i zrobić miejsce na zmianę używanego frameworka DI (Użyj fasady w głównej aplikacji (aplikacja sieci Web, interfejs WWW, pulpit) ..itp.).


1

W fabryce możesz grupować powiązane interfejsy, więc jeśli przekazane parametry mogą być pogrupowane w fabryce, to jest to również dobre rozwiązanie dla constructor overinjectiontego kodu *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Spójrz na konstruktor, musisz go tylko przekazać IAddressModelFactory, więc mniej parametrów *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

Widzisz w CustomerControllerwielu parametrach, tak, możesz to zobaczyć, ponieważ constructor overinjectiontak działa DI. I nie ma w tym nic złego CustomerController.

*) Kod pochodzi z nopCommerce.


1

Mówiąc najprościej, metoda wtrysku zależnego od fabrycznego implikuje odpowiednio mechanizm pchający i ciągnący.

Mechanizm ściągania : klasa pośrednio zależy od metody fabrycznej, która z kolei ma zależność od konkretnych klas.

Mechanizm pchający: Element główny może być skonfigurowany ze wszystkimi zależnymi elementami w jednym miejscu, co zapewnia wysoką konserwację i luźne połączenie.

W przypadku metody Factory odpowiedzialność nadal spoczywa na klasie (choć pośrednio) na tworzeniu nowego obiektu, gdzie podobnie jak w przypadku wstrzykiwania zależności odpowiedzialność ta jest zlecana na zewnątrz (kosztem przecieku abstrakcji)


0

Myślę, że są one ortogonalne i mogą być używane razem. Pozwól, że pokażę ci przykład, z którym ostatnio spotkałem się w pracy:

Używaliśmy frameworka Spring w Javie dla DI. Klasa singleton ( Parent) musiała utworzyć nowe obiekty innej klasy ( Child), a te miały złożoną współpracę:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

W tym przykładzie Parentmusi odbierać DepXinstancje tylko w celu przekazania ich do Childkonstruktora. Problemy z tym:

  1. Parentma większą wiedzę Childniż powinna
  2. Parent ma więcej współpracowników niż powinien
  3. Dodanie zależności Childwymaga zmianyParent

Wtedy zdałem sobie sprawę, Factoryże idealnie pasuje tutaj:

  1. Ukrywa wszystkie oprócz prawdziwych parametrów Childklasy, jak widaćParent
  2. Zawiera on wiedzę na temat tworzenia a Child, który może być scentralizowany w konfiguracji DI.

To jest Parentklasa uproszczona i ChildFactoryklasa:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

0

Wstrzykiwania zależności używasz, gdy dokładnie wiesz, jakiego rodzaju obiektów potrzebujesz w tym momencie. Podczas gdy w przypadku wzorca fabrycznego, po prostu delegujesz proces tworzenia obiektów do fabryki, ponieważ nie jesteś pewien, jakiego dokładnie rodzaju obiektów potrzebujesz.


-1

Używam obu do stworzenia strategii Inversion Of Control z większą czytelnością dla programistów, którzy muszą ją utrzymywać po mnie.

Używam fabryki do tworzenia różnych obiektów warstwy (biznes, dostęp do danych).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Inny programista to zobaczy i podczas tworzenia obiektu warstwy biznesowej zajrzy do BusinessFactory, a Intellisense daje programistowi wszystkie możliwe warstwy biznesowe do utworzenia. Nie musisz grać w grę, znajdź interfejs, który chcę utworzyć.

Ta struktura jest już Inwersją Kontroli. Nie jestem już odpowiedzialny za tworzenie konkretnego obiektu. Ale nadal musisz zapewnić Dependency Injection, aby móc łatwo zmieniać rzeczy. Tworzenie własnego niestandardowego wtrysku zależności jest niedorzeczne, więc używam Unity. W ramach CreateCarBusiness () proszę Unity, aby zdecydowała, która klasa należy do tej klasy i jaka jest jej żywotność.

Więc mój kod Struktura wstrzykiwania zależności fabrycznej to:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

Teraz mam zalety obu. Mój kod jest również bardziej czytelny dla innych programistów, jeśli chodzi o zakresy moich obiektów, których używam, zamiast Constructor Dependency Injection, który mówi tylko, że każdy obiekt jest dostępny podczas tworzenia klasy.

Używam tego do zmiany dostępu do bazy danych na niestandardową zakodowaną warstwę dostępu do danych podczas tworzenia testów jednostkowych. Nie chcę, aby moje testy jednostkowe komunikowały się z bazami danych, serwerami WWW, serwerami poczty e-mail itp. Muszą przetestować moją warstwę biznesową, ponieważ na tym polega inteligencja.


-4

Moim zdaniem użycie wstrzykiwania zależności jest znacznie lepsze, jeśli: 1. wdrażasz kod na małej partycji, ponieważ dobrze radzi sobie on w oddzielaniu jednego dużego kodu. 2. Testowalność jest jednym z przypadków, w których użycie DI jest w porządku, ponieważ można łatwo wyśmiewać nieprzężone obiekty. za pomocą interfejsów możesz łatwo wyśmiewać i testować każdy obiekt. 3. Możesz jednocześnie poprawiać każdą część programu bez konieczności kodowania drugiej części programu, ponieważ jest on luźno oddzielony.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.