Iniezione di dipendenza vs modello di fabbrica


498

La maggior parte degli esempi citati per l'uso dell'iniezione di dipendenza, possiamo risolvere anche usando il modello di fabbrica. Sembra che quando si tratta di utilizzo / progettazione la differenza tra iniezione di dipendenza e fabbrica sia sfocata o sottile.

Una volta qualcuno mi ha detto che è il modo in cui lo usi che fa la differenza!

Una volta ho usato StructureMap un contenitore DI per risolvere un problema, in seguito l'ho riprogettato per funzionare con una semplice fabbrica e ho rimosso i riferimenti a StructureMap.

Qualcuno può dirmi qual è la differenza tra loro e dove usare cosa, qual è la migliore pratica qui?


22
Questi due approcci non possono completarsi a vicenda: usare la Dependency Injection per iniettare le classi di fabbrica?
Richard Ev,

20
Sarebbe davvero bello se questa domanda avesse una risposta con un po 'di codice! Non vedo ancora come DI sarebbe utile / diverso dall'uso di una fabbrica per la creazione? Dovrai solo sostituire quella riga nella classe factory per cambiare l'oggetto / l'implementazione creata?
Gideon,

2
@gideon non ti costringerebbe a compilare la tua app, o almeno il modulo contenente la classe di fabbrica?
acido lisergico

1
@liortal sì, è vero. Ho fatto un lungo studio su DI da quel commento e ora capisco che DI porta il metodo di fabbrica un passo avanti.
Gideon,

1
Dai un'occhiata a questa grande risposta: stackoverflow.com/questions/4985455/… - lo esprime molto bene e fornisce esempi di codice.
Luis Perez,

Risposte:


294

Quando si utilizza una fabbrica, il codice è ancora effettivamente responsabile della creazione di oggetti. Con DI esternalizzi tale responsabilità a un'altra classe o ad un framework, che è separato dal tuo codice.


172
Il modello DI non richiede alcun framework. Puoi fare DI scrivendo manualmente fabbriche che fanno DI. I framework DI rendono tutto più semplice.
Esko Luontola,

28
@Perpetualcoder - Grazie @Esko - Non lasciarti sorprendere dalla parola framework che significa una libreria di terze parti avanzata.
Willcodejavaforfood,

4
+1 @willcode grazie! Quindi devi invece modificare i file config / xml. Vedo. Il link wiki en.wikipedia.org/wiki/… definisce lo schema di fabbrica comeManually-Injected Dependency
gideon,

5
Non ho il vantaggio di cambiare 1 riga di XML rispetto a cambiare 1 riga di codice. Potresti elaborare?
Rafael Eyng,

1
Ripetere la risposta OP sostituendo "DI" con "factory", ha ancora senso.
Edson Medina,

219

Suggerirei di mantenere i concetti chiari e semplici. Dependency Injection è più di un modello architettonico per accoppiare liberamente i componenti software. Il modello di fabbrica è solo un modo per separare la responsabilità di creare oggetti di altre classi in un'altra entità. Il modello di fabbrica può essere chiamato come strumento per implementare DI. L'iniezione di dipendenza può essere implementata in molti modi come DI usando i costruttori, usando la mappatura di file xml ecc.


4
È vero che Factory Pattern è uno dei modi per implementare l'iniezione delle dipendenze. Un altro vantaggio dell'utilizzo dell'iniezione di dipendenza rispetto al modello di fabbrica è che DI Frameworks ti darebbe flessibilità su come registrare le tue astrazioni rispetto ai tuoi tipi concreti. Come ad esempio Codice come Config, XML o Configurazione automatica. Tale flessibilità ti consentirà di gestire la durata dei tuoi oggetti o di decidere come e quando registrare le tue interfacce.
Teoman Shipahi,

1
Il modello di fabbrica offre un'astrazione di livello superiore rispetto a DI. Una factory può offrire opzioni di configurazione proprio come fa DI, ma può anche scegliere di nascondere tutti quei dettagli di configurazione, in modo che la factory possa decidere di passare a un'implementazione completamente diversa senza che il client lo sappia. DI da solo non lo consente. DI richiede al client di specificare le modifiche che desidera.
neurone

1
Bella risposta. Molti si confondono con quella domanda: "Quali patten dovrei scegliere?" In effetti, i modelli di progettazione sono solo un modo per risolvere il problema in situazioni adeguate. Se non sai quale modello di progettazione dovresti utilizzare o "Dove devo implementare il modello?" allora non ti serve in questo momento.
Benyi,

2
Penso che sia più preciso dire che Factory Pattern è uno strumento per implementare l'IoC (non DI). Si prega di notare che DI è una forma di IoC
Hooman Bahreini,

185

Iniezione di dipendenza

Invece di creare un'istanza delle parti stesse, un'auto richiede le parti necessarie per funzionare.

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;
    }
}

Fabbrica

Unisce i pezzi per creare un oggetto completo e nasconde il tipo concreto dal chiamante.

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;
    }   
}

Risultato

Come puoi vedere, Fabbriche e DI si completano a vicenda.

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

Ricordi i riccioli d'oro e i tre orsi? Bene, l'iniezione di dipendenza è un po 'così. Ecco tre modi per fare la stessa cosa.

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();
}

Esempio n. 1 - Questo è il peggio perché nasconde completamente la dipendenza. Se guardassi il metodo come una scatola nera, non avresti idea che richiedesse un'auto.

Esempio n. 2 - Questo è un po 'meglio perché ora sappiamo di aver bisogno di un'auto poiché passiamo in una fabbrica di automobili. Ma questa volta stiamo passando troppo perché tutto il metodo effettivamente necessario è un'auto. Stiamo passando in una fabbrica solo per costruire l'auto quando l'auto potrebbe essere costruita fuori dal metodo e fatta passare.

Esempio n. 3 - Questo è l'ideale perché il metodo richiede esattamente ciò di cui ha bisogno. Non troppo o troppo poco. Non devo scrivere una MockCarFactory solo per creare MockCars, posso passare la simulazione direttamente. È diretta e l'interfaccia non mente.

Questo Google Tech Talk di Misko Hevery è sorprendente ed è la base da cui ho tratto il mio esempio. http://www.youtube.com/watch?v=XcT4yYu_TTs


1
Il modello di fabbrica viene iniettato come DI.
Mangesh Pimpalkar,

7
@PhilGoetz Quello che stai descrivendo sembra più simile al modello di Service Locator. Hanno obiettivi simili, in quanto mirano a dissociare i servizi dai loro consumatori. Tuttavia, ci sono molti svantaggi nel modello di Service Locator. Principalmente, nascondere le dipendenze non è una buona cosa. Il consumatore deve ancora ottenere le sue dipendenze, ma invece di definire un'interfaccia chiara, vengono passate "segretamente" e si basano sullo stato globale. Nell'esempio, il consumatore non ha idea della fabbrica, chiede solo ciò di cui ha bisogno e non deve preoccuparsi di come è costruita quella necessità.
Despertar,

1
@MatthewWhited La maggior parte delle decisioni di progettazione ha un compromesso. Con DI, ottieni flessibilità, trasparenza e un sistema più testabile, ma a costo di esporre il tuo coraggio. Molte persone trovano questo un compromesso accettabile. Questo non vuol dire che DI sia sempre la soluzione migliore e questa domanda non riguarda questo. L'esempio ha lo scopo di mostrare la differenza tra DI e modello di fabbrica mostrando alcuni usi positivi e negativi di ciascuno.
Despertar,

3
Questo non è un modello DI, questa è solo un'implementazione di IoC. DI utilizza un ServiceLocator per determinare la giusta dipendenza e iniettarla nel costruttore durante la creazione dell'oggetto, il codice separa solo la creazione di oggetti dall'ambito della classe.
Diego Mendes,

3
@DiegoMendes Quello che stai descrivendo è un framework che automatizza DI. ServiceLocator come lo chiami fa il DI per te. Quello che sto mostrando è il modello stesso che non richiede quadri fantasiosi. Vedere stackoverflow.com/a/140655/1160036 o vedere en.wikipedia.org/wiki/… : "[elenco di framework] supporta l'iniezione di dipendenza ma non è necessario eseguire l'iniezione di dipendenza". Inoltre, "Un'iniezione è il passaggio di una dipendenza a un oggetto dipendente". Stai complicando troppo un concetto meravigliosamente semplice.
Despertar,

50

La ragione per cui Dependency Injection (DI) e Factory Patterns sono simili è perché sono due implementazioni di Inversion of Control (IoC) che è un'architettura software. In parole povere, sono due soluzioni allo stesso problema.

Quindi, per rispondere alla domanda, la principale differenza tra il modello Factory e DI è come si ottiene il riferimento all'oggetto. Con l'iniezione delle dipendenze, come suggerisce il nome, il riferimento viene iniettato o fornito al codice. Con il modello Factory il codice deve richiedere il riferimento in modo che il codice recuperi l'oggetto. Entrambe le implementazioni rimuovono o disaccoppiano il collegamento tra il codice e la classe o il tipo sottostante del riferimento oggetto utilizzato dal codice.

Vale la pena notare che i modelli Factory (o effettivamente i modelli Factory astratti che sono fabbriche che restituiscono nuove fabbriche che restituiscono riferimenti a oggetti) possono essere scritti per scegliere dinamicamente o collegarsi al tipo o alla classe di oggetto richiesti in fase di esecuzione. Questo li rende molto simili (anche più di DI) al modello di Service Locator che è un'altra implementazione dell'IoC.

Il modello di progettazione Factory è piuttosto vecchio (in termini di software) ed è in circolazione da un po 'di tempo. Dalla recente popolarità del modello architettonico IoC sta risorgendo.

Immagino quando si tratta di modelli di progettazione IoC: iniettori iniettano, localizzatori stanno localizzando e le fabbriche sono state refactored.


3
Questa è la risposta migliore ... altre risposte non menzionano l'IoC o non riconoscono che DI è una forma di IoC.
Hooman Bahreini,

Grazie, quando ho studiato il CIO per la prima volta ho quasi urlato che questa era solo un'altra forma del modello di fabbrica, risulta che sono davvero simili tra loro
Harvey Lin

40

Ci sono problemi che sono facili da risolvere con l'iniezione di dipendenza che non sono così facilmente risolvibili con una serie di fabbriche.

Alcune delle differenze tra, da un lato, l'inversione del controllo e l'iniezione di dipendenza (IOC / DI) e, dall'altro, un localizzatore di servizi o una suite di fabbriche (fabbrica), è:

IOC / DI è un ecosistema completo di oggetti e servizi di dominio in sé e per sé. Imposta tutto per te nel modo specificato. I vostri oggetti e servizi di dominio sono costruiti dal contenitore, e non costruire se stessi: essi pertanto non hanno alcun dipendenze sul contenitore o su qualsiasi fabbriche. IOC / DI consente un livello estremamente elevato di configurabilità, con tutta la configurazione in un unico posto (costruzione del contenitore) al livello più alto dell'applicazione (la GUI, il front-end Web).

Factory estrae parte della costruzione dei tuoi oggetti e servizi di dominio. Ma gli oggetti e i servizi di dominio sono ancora responsabili per capire come costruirsi e come ottenere tutto ciò da cui dipendono. Tutte queste dipendenze "attive" filtrano fino in fondo attraverso tutti i livelli dell'applicazione. Non esiste un unico posto dove andare per configurare tutto.


26

Uno svantaggio di DI è che non può inizializzare gli oggetti con la logica. Ad esempio, quando devo creare un personaggio con nome ed età casuali, DI non è la scelta rispetto al modello di fabbrica. Con le fabbriche, possiamo facilmente incapsulare l'algoritmo casuale dalla creazione di oggetti, che supporta uno dei modelli di progettazione chiamato "Incapsula ciò che varia".


22

La gestione del ciclo di vita è una delle responsabilità che i contenitori di dipendenza assumono oltre all'istanza e all'iniezione. Il fatto che il contenitore a volte mantenga un riferimento ai componenti dopo l'istanza è il motivo per cui viene chiamato "contenitore" e non una fabbrica. I contenitori per l'iniezione delle dipendenze di solito contengono solo un riferimento agli oggetti per i quali è necessario gestire i cicli di vita o che vengono riutilizzati per iniezioni future, come singoli o pesi volanti. Quando configurato per creare nuove istanze di alcuni componenti per ogni chiamata al contenitore, il contenitore di solito dimentica solo l'oggetto creato.

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


15

Credo che DI sia un tipo di strato di astrazione nelle fabbriche, ma forniscono anche benefici oltre l'astrazione. Una vera fabbrica sa come istanziare un singolo tipo e configurarlo. Un buon livello DI fornisce la possibilità, tramite la configurazione, di creare un'istanza e configurare molti tipi.

Ovviamente, per un progetto con alcuni tipi semplici che richiedono una logica aziendale relativamente stabile nella loro costruzione, il modello di fabbrica è semplice da capire, implementare e funziona bene.

OTOH, se hai un progetto contenente numerosi tipi le cui implementazioni ti aspetti di cambiare spesso, DI ti offre la flessibilità attraverso la sua configurazione per farlo in fase di esecuzione senza dover ricompilare le tue fabbriche.


14

Teoria

Ci sono due punti importanti da considerare:

  1. Chi crea oggetti

    • [Factory]: devi scrivere come deve essere creato l'oggetto. Hai una classe Factory separata che contiene la logica di creazione.
    • [Iniezione delle dipendenze]: in casi pratici vengono eseguiti da framework esterni (ad esempio in Java che sarebbe spring / ejb / guice). L'iniezione avviene "magicamente" senza esplicitare la creazione di nuovi oggetti
  2. Che tipo di oggetti gestisce:

    • [Factory]: solitamente responsabile della creazione di oggetti con stato
    • [Iniezioni di dipendenza] Più probabilità di creare oggetti senza stato

Esempio pratico su come utilizzare l'iniezione di fabbrica e di dipendenza in un singolo progetto

  1. Cosa vogliamo costruire

Modulo applicativo per la creazione di ordini che contiene più voci chiamate orderline.

  1. Architettura

Supponiamo di voler creare la seguente architettura di layer:

inserisci qui la descrizione dell'immagine

Gli oggetti di dominio possono essere oggetti memorizzati nel database. Repository (DAO) aiuta con il recupero di oggetti dal database. Il servizio fornisce API ad altri moduli. Consentono operazioni sul ordermodulo

  1. Livello di dominio e utilizzo delle fabbriche

Le entità che saranno nel database sono Order e OrderLine. L'ordine può avere più OrderLine. Relazione tra Order e OrderLine

Ora arriva una parte importante del design. I moduli al di fuori di questo dovrebbero creare e gestire OrderLines da soli? No. La riga ordine dovrebbe esistere solo quando si dispone di un ordine associato. Sarebbe meglio se si potesse nascondere implementaiton interno a classi esterne.

Ma come creare un ordine senza conoscere OrderLines?

Fabbrica

Qualcuno che vuole creare un nuovo ordine ha usato OrderFactory (che nasconderà i dettagli sul fatto in cui creiamo Ordine).

inserisci qui la descrizione dell'immagine

Ecco come apparirà all'interno dell'IDE. Le classi esterne al domainpacchetto verranno utilizzate al OrderFactoryposto del costruttore all'internoOrder

  1. Iniezione delle dipendenze L'iniezione delle dipendenze viene più comunemente utilizzata con livelli senza stato come repository e servizio.

OrderRepository e OrderService sono gestiti dal framework di iniezione delle dipendenze. Il repository è responsabile della gestione delle operazioni CRUD sul database. Il servizio inietta Repository e lo utilizza per salvare / trovare le classi di dominio corrette.

inserisci qui la descrizione dell'immagine


Potete per favore chiarire questo? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsNon capisco perché
Maksim Dmitriev il

2
È probabile che gli oggetti con stato si trovino nel livello di applicazione del dominio in cui si mappano i dati al database in cui di solito non si utilizza l'iniezione di dipendenza. La fabbrica viene spesso utilizzata per creare AggregateRoot dall'albero di oggetti complicati
Marcin Szymczak,

12

So che questa domanda è vecchia ma vorrei aggiungere i miei cinque centesimi,

Penso che l'iniezione di dipendenza (DI) sia in molti modi simile a un modello di fabbrica configurabile (FP), e in questo senso qualsiasi cosa tu possa fare con DI, sarai in grado di farlo con tale fabbrica.

In realtà, se ad esempio usi la primavera, hai la possibilità di autorizzare risorse (DI) o fare qualcosa del genere:

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

E poi usa quell'istanza 'mb' per fare qualsiasi cosa. Non è una chiamata a una fabbrica che ti restituirà un'istanza ??

L'unica vera differenza che noto tra la maggior parte degli esempi di FP è che puoi configurare ciò che "myBean" è in un xml o in un'altra classe, e un framework funzionerà come factory, ma a parte questo è la stessa cosa, e tu può avere sicuramente una Factory che legge un file di configurazione o ottiene l'implementazione di cui ha bisogno.

E se mi chiedi la mia opinione (e so che non l'hai fatto), credo che DI faccia la stessa cosa ma aggiunga solo più complessità allo sviluppo, perché?

bene, per prima cosa, per sapere qual è l'implementazione utilizzata per qualsiasi bean che autorizzi con DI, devi andare alla configurazione stessa.

ma ... che dire di quella promessa che non dovrete conoscere l'implementazione dell'oggetto che state usando? pfft! sul serio? quando usi un approccio come questo ... non sei lo stesso che scrive l'implementazione ?? e anche se non lo fai, non sei quasi sempre alla ricerca di come l'implementazione fa quello che dovrebbe fare ??

e per un'ultima cosa, non importa quanto un framework DI ti prometta che costruirai cose disaccoppiate da esso, senza dipendenze dalle loro classi, se stai usando un framework costruisci tutto ciò che lo attira, se devi cambiare l'approccio o il framework non sarà un compito facile ... MAI! ... ma dal momento che costruisci tutto intorno a quel particolare quadro invece di preoccuparti di quale sia la soluzione migliore per la tua attività, allora dovrai affrontare un problema.

In effetti, l'unica vera applicazione aziendale per un approccio FP o DI che posso vedere è se devi cambiare le implementazioni utilizzate in fase di esecuzione , ma almeno i framework che conosco non ti consentono di farlo, devi lasciare tutto perfetto nella configurazione in fase di sviluppo e se ne hai bisogno usa un altro approccio.

Quindi, se ho una classe che si comporta in modo diverso in due ambiti nella stessa applicazione (diciamo, due società di una holding) devo configurare il framework per creare due bean diversi e adattare il mio codice per usarli ciascuno. Non è lo stesso che scriverei qualcosa del genere:

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

lo stesso di questo:

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

E questo:

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

In ogni caso dovrai cambiare qualcosa nella tua applicazione, che si tratti di classi o file di configurazione, ma dovrai farlo per ridistribuirlo.

Non sarebbe bello fare una cosa del genere:

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

E in questo modo, si imposta il codice di fabbrica per ottenere la corretta implementazione in fase di esecuzione a seconda dell'impresa dell'utente registrato ?? Ora che sarebbe utile. Potresti semplicemente aggiungere un nuovo vaso con le nuove classi e impostare le regole forse anche anche in fase di esecuzione (o aggiungere un nuovo file di configurazione se lasci questa opzione aperta), nessuna modifica alle classi esistenti. Questa sarebbe una fabbrica dinamica!

non sarebbe più utile che dover scrivere due configurazioni per ciascuna impresa e magari avere anche due applicazioni diverse per ognuna ??

Puoi dirmi che non ho mai bisogno di fare lo switch in fase di runtime, quindi configuro l'app, e se eredito la classe o utilizzo un'altra implementazione cambio semplicemente la configurazione e la ridistribuzione. Ok, questo può essere fatto anche con una fabbrica. E ad essere sincero, quante volte lo fai? forse solo quando hai un'app che verrà utilizzata da qualche altra parte nella tua azienda e passerai il codice a un altro team e loro faranno cose del genere. Ma hey, questo può essere fatto anche con la fabbrica, e sarebbe ancora meglio con una fabbrica dinamica !!

Ad ogni modo, la sezione dei commenti è aperta per consentirmi di uccidermi.


3
Troppi sviluppatori pensano che i framework di Iniezione delle dipendenze siano stati creati per portare qualcosa di nuovo. Come ben spiegato, le fabbriche tradizionali (molto spesso la fabbrica astratta) possono svolgere lo stesso ruolo di inversione di dipendenza. Inversion vs Injection? Per me, l'unico "vantaggio" del framework Injection Dependency è che non dobbiamo cambiare / ricompilare il codice (poiché il più delle volte configurabile con XML come Spring) quando viene aggiunta / modificata una dipendenza. Perché evitare di ricompilare? Al fine di evitare alcuni potenziali errori umani mentre si cambia dipendenza / fabbrica. Ma con i nostri grandi IDE, il refactoring suona bene :)
Mik378,

6

IOC è un concetto che viene implementato in due modi. Creazione di dipendenza e iniezione di dipendenza, Factory / Abstract factory sono l'esempio della creazione di dipendenza. L'iniezione di dipendenza è costruttore, setter e interfaccia. Il nucleo del CIO non dipende dalle classi concrete, ma definisce l'abstract dei metodi (diciamo un'interfaccia / classe astratta) e usa quell'estratto per chiamare il metodo della classe concrete. Come il modello Factory restituisce la classe base o l'interfaccia. Iniezione di dipendenza simile utilizza la classe / interfaccia di base per impostare il valore per gli oggetti.


4

Con l'iniezione delle dipendenze il cliente non ha bisogno di ottenere le proprie dipendenze da solo, tutto preparato in anticipo.

Con le fabbriche, qualcuno deve chiamarle per portare gli oggetti generati nel luogo in cui sono necessari.

La differenza sta principalmente in questa linea in cui viene effettuata la chiamata alla fabbrica e il recupero dell'oggetto costruito.

Ma con le fabbriche devi scrivere questa 1 riga ovunque sia necessario un tale oggetto. Con DI devi solo creare il cablaggio (relazione tra utilizzo e oggetto creato) una volta e fare affidamento sulla presenza dell'oggetto in seguito ovunque. D'altra parte, DI spesso richiede un po 'più di lavoro (quanto dipende dal framework) sul lato della preparazione.


3

Ho avuto la stessa domanda non appena ho letto di DI e sono finito in questo post. Quindi finalmente questo è quello che ho capito, ma per favore correggimi se sbaglio.

"Molto tempo fa c'erano piccoli regni con i loro stessi organi di governo che controllavano e prendevano decisioni basate sulle proprie regole scritte. In seguito formarono un grande governo che eliminava tutti questi piccoli organi di governo che hanno un insieme di regole (costituzione) e sono attuati attraverso i tribunali"

Gli organi direttivi dei piccoli regni sono "Fabbriche"

Il grande governo è il "Dependency Injector".


1
Quindi QUANDO un programmatore considera un precedente piccolo governo che ora è grande? Con quale misura?
Prigioniero ZERO,

3

Puoi dare un'occhiata a questo link per un confronto tra i due (e altri) approcci in un esempio reale.

Fondamentalmente, quando i requisiti cambiano, si finisce per modificare più codice se si utilizzano fabbriche invece di DI.

Questo è valido anche con DI manuale (cioè quando non esiste un framework esterno che fornisce le dipendenze ai tuoi oggetti, ma le passi in ogni costruttore).


3

La maggior parte delle risposte qui spiega la differenza concettuale e i dettagli di implementazione di entrambi. Tuttavia, non sono stato in grado di trovare una spiegazione sulla differenza nell'applicazione quale IMO è il più importante e l'OP ha chiesto. Vorrei riaprire questo argomento ...

Una volta qualcuno mi ha detto che è il modo in cui lo usi che fa la differenza!

Esattamente. Nel 90% dei casi è possibile ottenere riferimenti agli oggetti utilizzando Factory o DI e di solito si finisce con quest'ultimo. In un altro 10% dei casi l'uso di Factory è solo il modo corretto . Questi casi includono l'ottenimento di oggetti per variabile nei parametri di runtime. Come questo:

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

In questo caso clientnon è possibile ottenere da DI (o almeno richiede qualche brutta soluzione). Quindi, come regola generale per prendere una decisione: se è possibile ottenere una dipendenza senza parametri calcolati in fase di esecuzione, si preferisce DI, altrimenti utilizzare Factory.


2

credo che DI sia un modo di configurare o creare istantaneamente un bean. Il DI può essere fatto in molti modi come costruttore, setter-getter, ecc.

Il modello di fabbrica è solo un altro modo di istanziare i fagioli. questo modello verrà utilizzato principalmente quando è necessario creare oggetti utilizzando il modello di progettazione di fabbrica, poiché durante l'utilizzo di questo modello non si configurano le proprietà di un bean, solo un'istanza dell'oggetto.

Controlla questo link: Iniezione delle dipendenze


2

Binoj,

Non penso che tu debba scegliere l'uno rispetto all'altro.

L'atto di spostare una classe o un'interfaccia dipendenti in un costruttore di classi o setter segue il modello DI. L'oggetto che passi al costruttore o al set può essere implementato con Factory.

Quando usare? Usa lo schema o gli schemi presenti nella timoniera dello sviluppatore. Con cosa si sentono più a loro agio e trovano più facile da capire.


2

Credo che 3 aspetti importanti governino gli oggetti e il loro utilizzo:
1. Istantanea (di una classe insieme all'inizializzazione se presente).
2. Iniezione (dell'istanza così creata) dove è richiesta.
3. Gestione del ciclo di vita (dell'istanza così creata).

Usando il modello Factory, si ottiene il primo aspetto (istanziazione) ma i restanti due sono discutibili. La classe che utilizza altre istanze deve codificare le fabbriche (invece di crearle) che ostacolano le capacità di accoppiamento allentate. Inoltre, gestione del ciclo di vitadelle istanze diventa una sfida in una grande applicazione in cui una fabbrica viene utilizzata in più punti (in particolare, se la fabbrica non gestisce il ciclo di vita dell'istanza che restituisce, diventa brutta).

Usando un DI (del modello IoC) d'altra parte, tutti e 3 vengono estratti al di fuori del codice (nel contenitore DI) e il bean gestito non ha bisogno di nulla su questa complessità. Loose Coupling , un obiettivo architettonico molto importante può essere raggiunto tranquillamente comodamente. Un altro importante obiettivo architettonico, la separazione delle preoccupazioni può essere raggiunto molto meglio delle fabbriche.

Considerando che le fabbriche possono essere adatte a piccole applicazioni, quelle più grandi sarebbero meglio scegliere DI rispetto alle fabbriche.


1

I miei pensieri:

Dependecy Injection: passa i collaboratori come parametri ai costruttori. Dependency Injection Framework: una fabbrica generica e configurabile per creare gli oggetti da passare come parametri ai costruttori.


1
Si, esattamente. Quasi tutte le menzioni di Dependency Injection (DI) in queste domande e risposte abusano del termine in contrasto con questa definizione. Un Dependency Injection Container (DIC) è il framework più comune che funge da factory generico e configurabile per creare oggetti.
CXJ

1

Un Injection Framework è un'implementazione del modello Factory.

Tutto dipende dalle tue esigenze. Se hai bisogno di implementare il modello di fabbrica in un'applicazione, è molto probabile che i tuoi requisiti saranno soddisfatti da una delle innumerevoli implementazioni del framework di iniezione.

Dovresti implementare la tua soluzione solo se i tuoi requisiti non possono essere soddisfatti da nessuno dei framework di terze parti. Più codice scrivi, più codice devi mantenere. Il codice è una responsabilità non un bene.

Gli argomenti su quale implementazione dovresti usare non sono così importanti come capire le esigenze architettoniche della tua applicazione.


1

Modello di progettazione di fabbrica

Il modello di design di fabbrica è caratterizzato da

  • Un'interfaccia
  • Classi di implementazione
  • Un'industria

Puoi osservare poche cose quando ti chiedi come di seguito

  • Quando la fabbrica creerà l'oggetto per le classi di implementazione: tempo di esecuzione o tempo di compilazione?
  • Cosa succede se si desidera cambiare l'implementazione in fase di esecuzione? - Non possibile

Questi sono gestiti dall'iniezione di dipendenza.

Iniezione di dipendenza

Puoi avere diversi modi in cui puoi iniettare dipendenza. Per semplicità, lascia andare con Interface Injection

In DI, il contenitore crea le istanze necessarie e le "inserisce" nell'oggetto.

Elimina così l'istanza statica.

Esempio:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

Da un valore nominale sembrano uguali

In termini molto semplici, Factory Pattern, Creation Pattern aiuta a crearci un oggetto: "Definisci un'interfaccia per creare un oggetto". Se disponiamo di un tipo di valore della chiave del pool di oggetti (ad es. Dizionario), passando la chiave alla Factory (mi riferisco al modello Factory semplice) è possibile risolvere il Tipo. Lavoro fatto! Dipendenze Injection Framework (come Structure Map, Ninject, Unity ... ecc.) D'altra parte sembra fare la stessa cosa.

Ma ... "Non reinventare la ruota"

Dal punto di vista architettonico è uno strato vincolante e "Non reinventare la ruota".

Per un'applicazione di livello aziendale, il concetto di DI è più un livello architettonico che definisce le dipendenze. Per semplificare ulteriormente ciò, puoi pensare a questo come a un progetto separato di classe, che risolve le dipendenze. L'applicazione principale dipende da questo progetto in cui il risolutore di dipendenze si riferisce ad altre implementazioni concrete e alla risoluzione delle dipendenze.

Inaddition a "GetType / Create" da una Factory, il più delle volte abbiamo bisogno di più funzionalità (capacità di usare XML per definire dipendenze, derisione e unit testing ecc.). Dato che hai fatto riferimento a Mappa struttura, guarda l' elenco delle caratteristiche Mappa struttura . È chiaramente più che semplicemente risolvere una semplice mappatura degli oggetti. Non reinventare la ruota!

Se tutto ciò che hai è un martello, tutto sembra un chiodo

A seconda delle tue esigenze e del tipo di applicazione che costruisci devi fare una scelta. Se ha solo pochi progetti (può essere uno o due ..) e comporta poche dipendenze, puoi scegliere un approccio più semplice. È come utilizzare ADO. Accesso ai dati .Net rispetto all'utilizzo di Entity Framework per una semplice 1 o 2 chiamate al database, in cui l'introduzione di EF è un problema in questo scenario.

Ma per un progetto più grande o se il tuo progetto diventa più grande, consiglio vivamente di avere un livello DI con un framework e fare spazio per cambiare il framework DI che usi (Usa una facciata nell'app principale (App Web, Web Api, Desktop ..eccetera.).


1

Con una fabbrica puoi raggruppare le interfacce correlate, quindi Se i parametri passati possono essere raggruppati in una fabbrica, allora è anche una buona soluzione per constructor overinjectionguardare questo codice *):

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;
    }

Guarda il costruttore, devi solo passare IAddressModelFactorylì, quindi meno parametri *):

 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,...

Vedi CustomerControllermolti parametri passati, Sì, puoi vederlo come, constructor overinjectionma è così che DI funziona. E non c'è niente di sbagliato nelCustomerController .

*) Il codice proviene da nopCommerce.


1

In termini semplici, il metodo Iniezione di dipendenza vs Fabbrica implica rispettivamente il meccanismo push vs pull.

Meccanismo di tiro : la classe ha indirettamente dipendenza dal metodo Factory che a sua volta ha dipendenza da classi concrete.

Meccanismo di spinta : il componente radice può essere configurato con tutti i componenti dipendenti in un'unica posizione, promuovendo così un'elevata manutenzione e un accoppiamento lento.

Con il metodo Factory la responsabilità spetta ancora alla classe (anche se indirettamente) di creare un nuovo oggetto in cui, come nel caso dell'iniezione di dipendenza, tale responsabilità è esternalizzata (a scapito della perdita di astrazione)


0

Penso che siano ortogonali e possano essere usati insieme. Lascia che ti mostri un esempio che mi sono imbattuto di recente al lavoro:

Stavamo usando il framework Spring in Java per DI. Una classe singleton ( Parent) doveva istanziare nuovi oggetti di un'altra classe ( Child) e quelli avevano collaboratori complessi:

@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);
        // ...
    }
}

In questo esempio, Parentdeve ricevere DepXistanze solo per passarle al Childcostruttore. Problemi con questo:

  1. Parentha più conoscenza di Childquanto dovrebbe
  2. Parent ha più collaboratori di quanto dovrebbe
  3. L'aggiunta di dipendenze Childcomporta il cambiamentoParent

Questo è quando ho realizzato a Factory si adatterebbe perfettamente qui:

  1. Nasconde tutti tranne i veri parametri di Child classe, come visto daParent
  2. Incapsula la conoscenza della creazione di a Child , che può essere centralizzata nella configurazione DI.

Questa è la Parentclasse semplificata e la ChildFactoryclasse:

@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

Usi l'iniezione di dipendenza quando sai esattamente quale tipo di oggetti hai bisogno in questo momento. Nel caso del modello di fabbrica, devi semplicemente delegare il processo di creazione degli oggetti alla fabbrica poiché non sei chiaro di quale tipo esatto di oggetti hai bisogno.


-1

Uso entrambi per creare una strategia di Inversion Of Control con maggiore leggibilità per gli sviluppatori che devono mantenerla dopo di me.

Uso una Factory per creare i miei diversi oggetti Layer (Business, Accesso ai dati).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Un altro sviluppatore lo vedrà e quando crea un oggetto di livello aziendale, cerca in BusinessFactory e Intellisense offre allo sviluppatore tutti i possibili livelli aziendali da creare. Non deve giocare, trova l'interfaccia che voglio creare.

Questa struttura è già Inversion Of Control. Non sono più responsabile della creazione dell'oggetto specifico. Ma devi comunque garantire l'iniezione delle dipendenze per poter cambiare facilmente le cose. Creare la tua Iniezione di dipendenza personalizzata è ridicolo, quindi uso Unity. All'interno di CreateCarBusiness () chiedo a Unity di risolvere quale classe appartiene a questa e la sua durata.

Quindi la mia struttura di iniezione di dipendenza dalla fabbrica di codice è:

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

Ora ho il vantaggio di entrambi. Il mio codice è anche più leggibile per gli altri sviluppatori rispetto agli ambiti dei miei oggetti che uso, invece che all'iniezione di dipendenza del costruttore che dice che ogni oggetto è disponibile quando viene creata la classe.

Uso questo per cambiare il mio accesso ai dati del database in un livello di accesso ai dati codificato personalizzato quando creo i test delle unità. Non voglio che i miei test unit possano comunicare con database, server web, server di posta elettronica ecc. Devono testare il mio livello aziendale perché è lì che si trova l'intelligence.


-4

L'utilizzo dell'iniezione di dipendenza è molto meglio secondo me se stai: 1. distribuendo il tuo codice in una piccola partizione, perché gestisce bene il disaccoppiamento di un grande codice. 2. la testabilità è uno dei casi in cui DI è ok da usare perché puoi deridere facilmente gli oggetti non disaccoppiati. con l'uso di interfacce puoi facilmente deridere e testare ogni oggetto. 3. puoi rivedere simultaneamente ogni parte del programma senza bisogno di codificare l'altra parte poiché è leggermente disaccoppiata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.