it-swarm.com.de

Abhängigkeitsinjektion vs. Fabrikmuster

Die meisten der für die Verwendung von Dependency Injection angeführten Beispiele können wir auch mit dem Factory-Muster lösen. Sieht so aus, als ob der Unterschied zwischen Abhängigkeitsinjektion und Fabrik in Bezug auf Verwendung/Design unscharf oder dünn ist.

Einmal hat mir jemand gesagt, dass es einen Unterschied macht, wie man es benutzt!

Ich habe einmal StructureMap einen DI-Container verwendet, um ein Problem zu lösen. Später habe ich ihn für die Arbeit mit einer einfachen Factory umgestaltet und Verweise auf StructureMap entfernt.

Kann mir jemand sagen, was der Unterschied zwischen ihnen ist und wo man was verwendet, was die beste Praxis hier ist?

478
Binoj Antony

Wenn Sie eine Fabrik verwenden, ist Ihr Code immer noch für die Erstellung von Objekten verantwortlich. Mit DI lagern Sie diese Verantwortung an eine andere Klasse oder ein Framework aus, das von Ihrem Code getrennt ist.

284

Ich würde vorschlagen, die Konzepte schlicht und einfach zu halten. Dependency Injection ist eher ein Architekturmuster für das lose Koppeln von Softwarekomponenten. Das Factory-Muster ist nur eine Möglichkeit, die Verantwortung für das Erstellen von Objekten anderer Klassen auf eine andere Entität zu verteilen. Factory-Pattern kann als Tool zur Implementierung von DI aufgerufen werden. Das Einfügen von Abhängigkeiten kann auf viele Arten implementiert werden, z.

213
Perpetualcoder

Abhängigkeitsinjektion

Anstatt die Teile selbst zu instanziieren, wird ein Auto fragt ​​nach den Teilen, die es benötigt, um zu funktionieren.

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

Factory

Fügt die Teile zu einem vollständigen Objekt zusammen und verbirgt den konkreten Typ vor dem Aufrufer.

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

Ergebnis

Wie Sie sehen, ergänzen sich Factories und DI.

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

Erinnerst du dich an Goldlöckchen und die drei Bären? Nun, Abhängigkeitsinjektion ist so ähnlich. Hier sind drei Möglichkeiten, das Gleiche zu tun.

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

Beispiel 1 - Dies ist das Schlimmste, da die Abhängigkeit vollständig ausgeblendet wird. Wenn Sie die Methode als Black Box betrachten, haben Sie keine Ahnung, dass ein Auto erforderlich ist.

Beispiel 2 - Das ist ein bisschen besser, weil wir jetzt wissen, dass wir ein Auto brauchen, da wir in einer Autofabrik vorbeikommen. Diesmal überholen wir uns jedoch zu sehr, da eigentlich nur ein Auto benötigt wird. Wir kommen in einer Fabrik vorbei, nur um das Auto zu bauen, wenn das Auto außerhalb der Methode gebaut und übergeben werden könnte.

Beispiel # - Dies ist ideal, da die Methode nach gena den Anforderungen fragt. Nicht zu viel oder zu wenig. Ich muss keine MockCarFactory schreiben, nur um MockCars zu erstellen. Ich kann das Mock direkt weitergeben. Es ist direkt und die Schnittstelle lügt nicht.

Dieser Google Tech Talk von Misko Hevery ist erstaunlich und die Grundlage für das, woraus ich mein Beispiel abgeleitet habe. http://www.youtube.com/watch?v=XcT4yYu_TTs

174
Despertar

Der Grund für die Ähnlichkeit von Dependency Injection (DI) und Factory Patterns liegt darin, dass es sich um zwei Implementierungen von Inversion of Control (IoC) handelt, einer Softwarearchitektur. Einfach ausgedrückt sind es zwei Lösungen für dasselbe Problem.

Um die Frage zu beantworten, besteht der Hauptunterschied zwischen dem Factory-Muster und DI darin, wie die Objektreferenz erhalten wird. Bei Abhängigkeitsinjektion wird, wie der Name schon sagt, die Referenz in Ihren Code injiziert oder diesem übergeben. Mit dem Factory-Muster muss Ihr Code die Referenz anfordern, damit Ihr Code das Objekt abruft. Beide Implementierungen entfernen oder entkoppeln die Verknüpfung zwischen dem Code und der zugrunde liegenden Klasse oder dem zugrunde liegenden Typ der vom Code verwendeten Objektreferenz.

Es ist erwähnenswert, dass Factory-Muster (oder abstrakte Factory-Muster, die Fabriken sind, die neue Fabriken zurückgeben, die Objektreferenzen zurückgeben) geschrieben werden können, um den Typ oder die Klasse des Objekts, das zur Laufzeit angefordert wird, dynamisch auszuwählen oder zu verknüpfen. Dies macht sie dem Service Locator-Muster, das eine weitere Implementierung der IoC darstellt, sehr ähnlich (noch ähnlicher als DI).

Das Factory-Designmuster ist (in Bezug auf die Software) ziemlich alt und gibt es schon eine Weile. Seit der jüngsten Popularität des Architekturmusters IoC erlebt es ein Wiederaufleben.

Ich denke, wenn es um IoC-Entwurfsmuster geht: Injektoren werden injiziert, Ortungsgeräte werden lokalisiert und die Fabriken wurden überarbeitet.

42
Tom Maher

Es gibt Probleme, die mit der Abhängigkeitsinjektion leicht zu lösen sind und die mit einer Reihe von Fabriken nicht so einfach zu lösen sind.

Ein Unterschied zwischen der Inversion der Steuerung und der Abhängigkeitsinjektion (IOC/DI) und einem Service-Locator oder einer Suite von Fabriken (Werk) besteht zum einen darin,

IOC/DI ist ein vollständiges Ökosystem von Domänenobjekten und -diensten an und für sich. Es richtet alles für Sie so ein, wie Sie es spezifizieren. Ihre Domänenobjekte und -dienste werden vom Container erstellt und erstellen sich nicht von selbst. Sie haben daher keine any - Abhängigkeiten vom Container oder von Fabriken. IOC/DI ermöglicht einen extrem hohen Grad an Konfigurierbarkeit, wobei sich die gesamte Konfiguration an einem einzigen Ort (Aufbau des Containers) auf der obersten Ebene Ihrer Anwendung befindet (GUI, Web-Front-End).

Factory abstrahiert einige der Konstruktionen Ihrer Domänenobjekte und -dienste. Domänenobjekte und -dienste sind jedoch weiterhin dafür verantwortlich, herauszufinden, wie sie sich selbst konstruieren und wie sie all die Dinge erhalten, von denen sie abhängen. Alle diese "aktiven" Abhängigkeiten werden durch alle Ebenen in Ihrer Anwendung gefiltert. Es gibt keinen einzigen Ort, an dem Sie alles konfigurieren können.

40
yfeldblum

Ein Nachteil von DI ist, dass es keine Objekte mit Logik initialisieren kann. Wenn ich zum Beispiel einen Charakter mit zufälligem Namen und Alter erstellen muss, ist DI nicht die Wahl vor dem Factory-Muster. In Fabriken können wir einfach den Zufallsalgorithmus aus der Objekterstellung kapseln, der eines der Entwurfsmuster namens "Verkapseln, was variiert" unterstützt.

25
BinMaster

Das Lebenszyklusmanagement ist neben der Instanziierung und Injektion eine der Aufgaben, die Abhängigkeitscontainer übernehmen. Die Tatsache, dass der Container manchmal nach der Instanziierung einen Verweis auf die Komponenten behält, ist der Grund, warum er als "Container" und nicht als Factory bezeichnet wird. In Abhängigkeitsinjektionscontainer enthalten in der Regel nur Verweise auf Objekte, die für die Verwaltung der Lebenszyklen benötigt werden oder die für zukünftige Injektionen wiederverwendet werden, z. B. Singletons oder Fliehgewichte. Wenn der Container so konfiguriert ist, dass für jeden Aufruf des Containers neue Instanzen einiger Komponenten erstellt werden, wird das erstellte Objekt normalerweise nur vergessen.

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

22
Pup

Ich glaube, DI ist eine Art Abstraktionsschicht für Fabriken, aber sie bieten auch Vorteile, die über die Abstraktion hinausgehen. Eine echte Fabrik weiß, wie ein einzelner Typ instanziiert und konfiguriert wird. Eine gute DI-Schicht bietet die Möglichkeit, durch Konfiguration viele Typen zu instanziieren und zu konfigurieren.

Für ein Projekt mit wenigen einfachen Typen, für deren Konstruktion eine relativ stabile Geschäftslogik erforderlich ist, ist das Factory-Muster offensichtlich einfach zu verstehen, zu implementieren und funktioniert gut.

OTOH, wenn Sie ein Projekt mit zahlreichen Typen haben, deren Implementierungen Sie voraussichtlich häufig ändern, bietet DI Ihnen durch seine Konfiguration die Flexibilität, dies zur Laufzeit zu tun, ohne dass Sie Ihre Fabriken neu kompilieren müssen.

16
Will

Theorie

Es sind zwei wichtige Punkte zu beachten:

  1. Wer schafft Objekte

    • [Factory]: Sie müssen schreiben, wie das Objekt erstellt werden soll. Sie haben eine separate Factory-Klasse, die die Erstellungslogik enthält.
    • [Abhängigkeitsinjektion]: In der Praxis erfolgt die Injektion durch externe Frameworks (zum Beispiel in Java das wäre spring/ejb/guice). Die Injektion erfolgt "magisch" ohne explizite Erstellung neuer Objekte
  2. Welche Art von Objekten verwaltet es:

    • [Factory]: In der Regel für die Erstellung zustandsbehafteter Objekte verantwortlich
    • [Abhängigkeitsinjektionen] Es ist wahrscheinlicher, dass zustandslose Objekte erstellt werden

Praktisches Beispiel für die Verwendung von Factory- und Dependency-Injection in einem einzelnen Projekt

  1. Was wir bauen wollen

Anwendungsmodul zum Erstellen von Aufträgen, die mehrere Einträge enthalten, die als Auftragszeile bezeichnet werden.

  1. Die Architektur

Angenommen, wir möchten folgende Ebenenarchitektur erstellen:

enter image description here

Domänenobjekte können Objekte sein, die in der Datenbank gespeichert sind. Das Repository (DAO) hilft beim Abrufen von Objekten aus der Datenbank. Der Dienst stellt eine API für andere Module bereit. Erlaubt Operationen auf dem order Modul

  1. Domain Layer und Nutzung von Fabriken

Entitäten, die in der Datenbank sein werden, sind Order und OrderLine. Auftrag kann mehrere Auftragspositionen haben. Relationship between Order and OrderLine

Jetzt kommt ein wichtiger Designteil. Sollten Module außerhalb dieses Moduls eigene Bestellpositionen erstellen und verwalten? Die Bestellposition sollte nur existieren, wenn Sie eine Bestellung zugeordnet haben. Es wäre am besten, wenn Sie die interne Implementierung vor externen Klassen verbergen könnten.

Aber wie kann man eine Bestellung erstellen, ohne über OrderLines Bescheid zu wissen?

Fabrik

Jemand, der eine neue Bestellung erstellen möchte, verwendet OrderFactory (wodurch Details darüber, wie wir eine Bestellung erstellen, ausgeblendet werden).

enter image description here

So sieht es in IDE aus. Klassen außerhalb des Pakets domain verwenden OrderFactory anstelle des Konstruktors innerhalb von Order

  1. Abhängigkeitsinjektion Die Abhängigkeitsinjektion wird häufiger bei zustandslosen Layern wie Repository und Service verwendet.

OrderRepository und OrderService werden vom Abhängigkeitsinjektionsframework verwaltet. Das Repository ist für die Verwaltung der CRUD-Operationen in der Datenbank verantwortlich. Der Dienst injiziert das Repository und verwendet es, um die richtigen Domänenklassen zu speichern/zu finden.

enter image description here

13
Marcin Szymczak

Ich weiß, dass diese Frage alt ist, aber ich möchte meine fünf Cent hinzufügen,

Ich denke, dass Dependency Injection (DI) in vielerlei Hinsicht wie ein konfigurierbares Factory Pattern (FP) ist, und in diesem Sinne alles, was Sie mit DI tun können, werden Sie in der Lage sein, es mit einer solchen Factory zu tun.

Wenn Sie zum Beispiel spring verwenden, haben Sie die Möglichkeit, Ressourcen automatisch zu verdrahten (DI) oder folgendermaßen vorzugehen:

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

Und dann benutze diese 'mb'-Instanz, um etwas zu tun. Ist das nicht ein Anruf bei einer Fabrik, die Ihnen eine Instanz zurückgibt?

Der einzige wirkliche Unterschied, den ich zwischen den meisten FP - Beispielen bemerke, besteht darin, dass Sie konfigurieren können, was "myBean" in einer XML-Datei oder in einer anderen Klasse ist, und dass ein Framework wie die Factory funktioniert, aber ansonsten ist es dasselbe Sie können sicher eine Factory haben, die eine Konfigurationsdatei liest oder die Implementierung nach Bedarf abruft.

Und wenn Sie mich nach meiner Meinung fragen (und ich weiß, dass Sie es nicht getan haben), glaube ich, dass DI dasselbe tut, aber der Entwicklung einfach mehr Komplexität verleiht. Warum?

damit Sie wissen, welche Implementierung für eine Bean verwendet wird, die Sie automatisch mit DI verdrahten, müssen Sie zunächst die Konfiguration selbst aufrufen.

aber ... was ist mit dem Versprechen, dass Sie die Implementierung des von Ihnen verwendeten Objekts nicht kennen müssen? pfft! Ernsthaft? Wenn Sie einen Ansatz wie diesen verwenden ... sind Sie nicht derselbe, der die Implementierung schreibt? und selbst wenn nicht, schaust du fast die ganze Zeit, wie die Implementierung das tut, was sie tun soll?

und für eine letzte Sache es ist egal, wie viel ein DI-Framework verspricht Sie, dass Sie Dinge bauen entkoppelt davon, ohne Abhängigkeiten zu ihren Klassen, wenn Sie Wenn Sie ein Framework verwenden, bauen Sie alles darauf auf, wenn Sie den Ansatz oder das Framework ändern müssen, wird es keine leichte Aufgabe sein ... ÜBERHAUPT! ... aber da Sie alles darauf aufbauen Anstatt sich Gedanken über die beste Lösung für Ihr Unternehmen zu machen, werden Sie dabei mit einem großen Problem konfrontiert.

Die einzige echte Geschäftsanwendung für einen FP - oder DI-Ansatz, die ich sehen kann, ist, wenn Sie die Implementierungen ändern müssen, die zum Zeitpunkt Laufzeit verwendet werden, aber zumindest die mir bekannten Frameworks Wenn Sie dies nicht zulassen, müssen Sie zur Entwicklungszeit alles perfekt in der Konfiguration belassen und einen anderen Ansatz verwenden, wenn Sie dies benötigen.

Wenn ich also eine Klasse habe, die in zwei Bereichen in derselben Anwendung unterschiedlich abschneidet (z. B. zwei Unternehmen einer Holding), muss ich das Framework so konfigurieren, dass zwei verschiedene Beans erstellt werden, und meinen Code für die jeweilige Verwendung anpassen. Ist das nicht das Gleiche, als würde ich einfach so etwas schreiben:

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

das gleiche wie das:

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

Und das:

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 jedem Fall müssen Sie etwas in Ihrer Anwendung ändern, egal ob Klassen oder Konfigurationsdateien, aber Sie müssen es tun und erneut bereitstellen.

Wäre es nicht schön, einfach so etwas zu machen:

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

Und auf diese Weise setzen Sie den Code der Factory, um abhängig vom angemeldeten Benutzerunternehmen zur Laufzeit die richtige Implementierung zu erhalten? Nun, das wäre hilfreich. Sie könnten einfach eine neue JAR mit den neuen Klassen hinzufügen und die Regeln möglicherweise sogar zur Laufzeit festlegen (oder eine neue Konfigurationsdatei hinzufügen, wenn Sie diese Option offen lassen), ohne Änderungen an vorhandenen Klassen vorzunehmen. Dies wäre eine dynamische Fabrik!

wäre das nicht hilfreicher, als zwei Konfigurationen für jedes Unternehmen zu schreiben und vielleicht sogar zwei verschiedene Anwendungen für jedes Unternehmen zu haben?

Sie können mir sagen, dass ich den Wechsel nie zur Laufzeit durchführen muss, also konfiguriere ich die App. Wenn ich die Klasse erbe oder eine andere Implementierung verwende, ändere ich einfach die Konfiguration und stelle sie erneut bereit. Ok, das geht auch mit einer Fabrik. Und sei ehrlich, wie oft machst du das? Vielleicht nur, wenn Sie eine App haben, die irgendwo anders in Ihrem Unternehmen verwendet wird, und Sie den Code an ein anderes Team weitergeben, und sie werden solche Dinge tun. Aber hey, das geht auch mit der Fabrik und wäre mit einer dynamischen Fabrik noch besser !!

Wie auch immer, der Kommentarbereich ist offen, damit du mich tötest.

12
Frank Orellana

IOC ist ein Konzept, das auf zwei Arten umgesetzt wird. Erstellen von Abhängigkeiten und Einfügen von Abhängigkeiten, Factory/Abstract-Factory sind Beispiele für das Erstellen von Abhängigkeiten. Die Abhängigkeitsinjektion ist Konstruktor, Setter und Schnittstelle. Der Kern von IOC ist, nicht von den konkreten Klassen abhängig zu sein, sondern die Zusammenfassung von Methoden (z. B. eine Interface-/abstrakte Klasse) zu definieren und diese Zusammenfassung zu verwenden, um die Methode einer konkreten Klasse aufzurufen Gibt die Basisklasse oder das Interface zurück. Ähnlichkeitsabhängigkeitsinjektion Verwenden Sie die Basisklasse/das Interface, um den Wert für Objekte festzulegen.

6
Thakur

Bei der Abhängigkeitsinjektion muss der Client seine Abhängigkeiten nicht selbst ermitteln, sondern muss alles vorher vorbereiten.

Bei Fabriken muss jemand diese anrufen, um die generierten Objekte an den Ort zu bringen, an dem sie benötigt werden.

Der Unterschied liegt hauptsächlich in dieser einen Zeile, in der die Fabrik aufgerufen und das konstruierte Objekt abgerufen wird.

Aber bei Fabriken muss man diese 1 Zeile überall dort schreiben, wo man ein solches Objekt benötigt. Mit DI müssen Sie nur einmal die Verkabelung (Beziehung zwischen Nutzung und erstelltem Objekt) erstellen und sich danach überall auf die Anwesenheit des Objekts verlassen. Andererseits erfordert DI auf der Vorbereitungsseite oft etwas mehr Arbeit (wie viel davon vom Framework abhängt).

5
Kosi2801

Sie können sich diesen Link ansehen, um einen Vergleich der beiden (und anderer) Ansätze in zu erhalten ein echtes Beispiel.

Wenn sich die Anforderungen ändern, ändern Sie im Grunde genommen mehr Code, wenn Sie Fabriken anstelle von DI verwenden.

Dies gilt auch für die manuelle DI (d. H., Wenn es kein externes Framework gibt, das die Abhängigkeiten zu Ihren Objekten bereitstellt, Sie sie jedoch in jedem Konstruktor übergeben).

Ich hatte die gleiche Frage, sobald ich über DI gelesen hatte und bei diesem Beitrag gelandet war. Endlich habe ich das verstanden, aber bitte korrigiere mich, wenn ich falsch liege.

"Vor langer Zeit gab es kleine Königreiche mit eigenen Leitungsgremien, die ihre Entscheidungen nach ihren eigenen Regeln kontrollierten und fällten. Später bildete sich eine große Regierung, die all diese kleinen Leitungsgremien eliminierte, die ein Regelwerk (Verfassung) hatten und durch Gerichte umgesetzt wurden."

Die Regierungsorgane der kleinen Königreiche sind "Fabriken"

Die große Regierung ist der "Dependency Injector".

3
blueskin

ich glaube, dass DI eine Möglichkeit ist, eine Bean zu konfigurieren oder zu instanziieren. Der DI kann auf viele Arten wie Konstruktor, Setter-Getter usw. ausgeführt werden.

Das Factory-Muster ist nur eine andere Art, Bohnen zu instantiieren. Dieses Muster wird hauptsächlich verwendet, wenn Sie Objekte mit dem Factory-Design-Muster erstellen müssen, da Sie bei Verwendung dieses Musters die Eigenschaften einer Bean nicht konfigurieren, sondern nur das Objekt instanziieren.

Überprüfen Sie diesen Link: Dependency Injection

2
harshit

Binoj,

Ich glaube nicht, dass Sie sich für einen entscheiden müssen.

Das Verschieben einer abhängigen Klasse oder Schnittstelle in einen Klassenkonstruktor oder Setter folgt dem DI-Muster. Das Objekt, das Sie an den Konstruktor oder das Set übergeben, kann mit Factory implementiert werden.

Wann verwenden? Verwenden Sie das oder die Muster, die sich in Ihrem Entwickler-Steuerhaus befinden. Was fühlen sie sich am wohlsten und am leichtesten zu verstehen.

2
Jason Slocomb

Ich glaube, 3 wichtige Aspekte bestimmen Objekte und ihre Verwendung:
1. Instanziierung (einer Klasse zusammen mit der Initialisierung, falls vorhanden).
2. Injection (der so erstellten Instanz) wo es benötigt wird.
3. Lebenszyklusverwaltung (der so erstellten Instanz).

Mit dem Factory-Muster wird der erste Aspekt (Instanziierung) erreicht, die restlichen beiden sind fraglich. Die Klasse, die andere Instanzen verwendet, muss die Fabriken fest codieren (anstatt dass Instanzen erstellt werden), was lose Kopplungsfähigkeiten behindert. Darüber hinaus wird Lebenszyklusverwaltung von Instanzen zu einer Herausforderung in einer großen Anwendung, in der eine Factory an mehreren Orten verwendet wird (insbesondere, wenn die Factory den Lebenszyklus der zurückgegebenen Instanz nicht verwaltet, wird er abgerufen) hässlich).

Bei Verwendung eines DI (mit IoC-Muster) werden dagegen alle 3 außerhalb des Codes (zum DI-Container) abstrahiert, und die verwaltete Bean benötigt nichts an dieser Komplexität. Loose Coupling, ein sehr wichtiges architektonisches Ziel kann leise bequem erreicht werden. Ein weiteres wichtiges architektonisches Ziel, die Trennung von Belangen kann viel besser als Fabriken erreicht werden.

Während die Fabriken möglicherweise für kleine Anwendungen geeignet sind, sollten große Fabriken DI vorziehen.

2
Anand Vemula

Die meisten Antworten hier erklären den konzeptionellen Unterschied und die Implementierungsdetails von beiden. Ich konnte jedoch keine Erklärung für den Unterschied in der Anwendung finden, welche IMO die wichtigste ist, und das OP fragte nach. Lassen Sie mich dieses Thema noch einmal eröffnen ...

Einmal hat mir jemand gesagt, dass es einen Unterschied macht, wie man es benutzt!

Genau. In 90% der Fälle können Sie mithilfe von Factory oder DI einen Objektverweis erhalten. In der Regel erhalten Sie letztere. In weiteren 10% Fällen ist die Verwendung von Factory nur auf korrekte Weise. Diese Fälle umfassen das Abrufen von Objekten nach Variablen zu Laufzeitparametern. So was:

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

In diesem Fall ist das Abrufen von client von DI nicht möglich (oder erfordert zumindest eine hässliche Problemumgehung). Als allgemeine Regel für die Entscheidung gilt: Wenn eine Abhängigkeit ohne zur Laufzeit berechnete Parameter erhalten werden kann, wird DI bevorzugt, andernfalls wird Factory verwendet.

1
neleus

Factory Design Pattern

Das Fabrikmuster ist gekennzeichnet durch

  • Eine Schnittstelle
  • Implementierungsklassen
  • Eine Fabrik

Sie können einige Dinge beobachten, wenn Sie sich wie folgt fragen

  • Wann erstellt die Factory ein Objekt für die Implementierungsklassen - Laufzeit oder Kompilierungszeit?
  • Was ist, wenn Sie die Implementierung zur Laufzeit wechseln möchten? - nicht möglich

Diese werden durch Abhängigkeitsinjektion behandelt.

Abhängigkeitsinjektion

Sie können Abhängigkeiten auf verschiedene Arten injizieren. Der Einfachheit halber lassen Sie sich mit Interface Injection gehen

In DI erstellt der Container die erforderlichen Instanzen und "injiziert" sie in das Objekt.

Somit entfällt die statische Instanziierung.

Beispiel:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

Mit einer Factory können Sie verwandte Schnittstellen gruppieren. Wenn die übergebenen Parameter in einer Factory gruppiert werden können, ist dies auch eine gute Lösung für constructor overinjection schau dir diesen Code an *):

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

Schau dir den Konstruktor an, dort musst du nur IAddressModelFactory übergeben, also weniger Parameter *):

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

Sie sehen in CustomerController viele übergebene Parameter. Ja, Sie können dies als constructor overinjection aber so funktioniert DI. Und nein, nichts ist falsch mit dem CustomerController.

*) Code stammt von nopCommerce.

1

Meine Gedanken:

Dependecy Injection: Übergeben Sie Mitarbeiter als Parameter an die Konstruktoren. Dependency Injection Framework: Eine generische und konfigurierbare Factory zum Erstellen der Objekte, die als Parameter an die Konstruktoren übergeben werden sollen.

1
bloparod

In einfachen Worten impliziert die Methode "Dependency Injection vs Factory" einen Push vs Pull-Mechanismus.

Pull-Mechanismus: Klasse ist indirekt von der Factory-Methode abhängig, die wiederum von konkreten Klassen abhängt.

Push-Mechanismus: Die Root-Komponente kann mit allen abhängigen Komponenten an einem einzigen Ort konfiguriert werden, wodurch ein hoher Wartungsaufwand und eine lose Kopplung gefördert werden.

Bei der Factory-Methode liegt die Verantwortung immer noch bei der Klasse (wenn auch indirekt), um ein neues Objekt zu erstellen.

1
Rahul Agarwal

Ein Injection Framework ist eine Implementierung des Factory Pattern.

Alles hängt von Ihren Anforderungen ab. Wenn Sie das Factory-Pattern in einer Anwendung implementieren müssen, werden Ihre Anforderungen höchstwahrscheinlich von einer der unzähligen Implementierungen von Injection Frameworks erfüllt.

Sie sollten Ihre eigene Lösung nur dann einführen, wenn Ihre Anforderungen von keinem der Frameworks von Drittanbietern erfüllt werden können. Je mehr Code Sie schreiben, desto mehr Code müssen Sie verwalten. Code ist eine Verbindlichkeit, kein Vermögenswert.

Argumente darüber, welche Implementierung Sie verwenden sollten, sind nicht so wichtig wie das Verständnis der architektonischen Anforderungen Ihrer Anwendung.

1
Mick

Von einem Nennwert sehen sie gleich aus

In sehr einfachen Worten, Factory Pattern, ein Creational Pattern hilft uns, ein Objekt zu erstellen - "Definieren Sie eine Schnittstelle zum Erstellen eines Objekts". Wenn wir eine Art Schlüsselwert-Objektpool haben (z. B. Dictionary), können Sie den Typ auflösen, indem Sie den Schlüssel an die Factory übergeben (ich beziehe mich auf das Simple Factory Pattern). Job erledigt! Das Abhängigkeitsinjektions-Framework (wie Structure Map, Ninject, Unity ... usw.) scheint dagegen dasselbe zu tun.

Aber ... "erfinde das Rad nicht neu"

Aus architektonischer Sicht ist es eine verbindliche Schicht und "erfinde das Rad nicht neu".

Für eine Unternehmensanwendung ist das DI-Konzept eher eine Architekturschicht, die Abhängigkeiten definiert. Um dies weiter zu vereinfachen, können Sie sich dies als ein separates Klassenbibliotheksprojekt vorstellen, das die Abhängigkeitsauflösung ausführt. Die Hauptanwendung hängt von diesem Projekt ab, in dem sich der Abhängigkeitsauflöser auf andere konkrete Implementierungen und die Abhängigkeitsauflösung bezieht.

Zusätzlich zu "GetType/Create" aus einer Factory werden in den meisten Fällen mehr Funktionen benötigt (XML-Fähigkeit zum Definieren von Abhängigkeiten, Verspotten und Testen von Einheiten usw.). Da Sie sich auf Structure Map bezogen haben, lesen Sie die Structure Map Feature List . Es ist eindeutig mehr als nur das Auflösen einer einfachen Objektzuordnung. Das Rad nicht neu erfinden!

Wenn Sie nur einen Hammer haben, sieht alles aus wie ein Nagel

Abhängig von Ihren Anforderungen und der Art der Anwendung, die Sie erstellen, müssen Sie eine Auswahl treffen. Wenn es nur wenige Projekte hat (möglicherweise eines oder zwei) und nur wenige Abhängigkeiten aufweist, können Sie einen einfacheren Ansatz wählen. Die Verwendung von ADO .Net-Datenzugriff anstelle von Entity Framework für einfache 1 oder 2 Datenbankaufrufe, wobei die Einführung von EF in diesem Szenario ein Overkill ist.

Aber für ein größeres Projekt oder wenn Ihr Projekt größer wird, würde ich dringend empfehlen, eine DI-Ebene mit einem Framework zu haben und Platz zu schaffen, um das von Ihnen verwendete DI-Framework zu ändern (Verwenden Sie eine Fassade in der Haupt-App (Web App, Web API, Desktop) ..usw.).

1
Dhanuka777

Ich denke, dass diese orthogonal sind und zusammen verwendet werden können. Lassen Sie mich Ihnen ein Beispiel zeigen, auf das ich kürzlich bei der Arbeit gestoßen bin:

Wir verwendeten das Spring-Framework in Java für DI. Eine Singleton-Klasse (Parent) musste neue Objekte einer anderen Klasse (Child) instanziieren, und diese hatte komplexe Mitarbeiter:

@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 diesem Beispiel muss ParentDepX Instanzen empfangen, um sie an den Konstruktor Child zu übergeben. Probleme damit:

  1. Parent hat mehr Wissen über Child als es sollte
  2. Parent hat mehr Mitarbeiter als es sollte
  3. Das Hinzufügen von Abhängigkeiten zu Child umfasst das Ändern von Parent

Zu diesem Zeitpunkt wurde mir klar, dass ein Factory hier perfekt passen würde:

  1. Es verbirgt alle bis auf die wahren Parameter der Klasse Child, wie sie von Parent gesehen werden.
  2. Es enthält das Wissen zum Erstellen eines Child, das in der DI-Konfiguration zentralisiert werden kann.

Dies ist die vereinfachte Klasse Parent und die Klasse ChildFactory:

@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
Martín Coll