Abhängigkeitsinjektion gegen Fabrikmuster


498

Die meisten der für die Verwendung von Dependency Injection angeführten Beispiele können wir auch anhand des Factory-Musters lösen. Es sieht so aus, als ob der Unterschied zwischen Abhängigkeitsinjektion und Werkseinstellung bei Verwendung / Design unscharf oder dünn ist.

Einmal hat mir jemand gesagt, dass es einen Unterschied macht, wie Sie es verwenden!

Ich habe einmal StructureMap, einen DI-Container, verwendet, um ein Problem zu lösen. Später habe ich ihn neu gestaltet, um mit einer einfachen Factory zu arbeiten, und Verweise auf StructureMap entfernt.

Kann mir jemand sagen, was der Unterschied zwischen ihnen ist und wo was zu verwenden ist, was hier die beste Vorgehensweise ist?


21
Können sich diese beiden Ansätze nicht gegenseitig ergänzen: Verwenden von Dependency Injection zum Injizieren von Factory-Klassen?
Richard Ev

20
Wäre wirklich schön, wenn diese Frage eine Antwort mit etwas Code hätte! Ich sehe immer noch nicht, wie DI nützlich / anders wäre, als eine Fabrik für die Erstellung zu verwenden. Sie müssen nur diese eine Zeile in der Factory-Klasse ersetzen, um zu ändern, welches Objekt / welche Implementierung erstellt wird.
Gideon

2
@gideon würde dich das nicht zwingen, deine App oder zumindest das Modul mit der Factory-Klasse zu kompilieren?
Lysergsäure

1
@liortal yep das stimmt. Habe seit diesem Kommentar eine lange Studie über DI durchgeführt und jetzt verstehe ich, dass DI die Fabrikmethode einen Schritt voraus macht.
Gideon

1
Schauen Sie sich diese großartige Antwort an: stackoverflow.com/questions/4985455/… - er formuliert sie sehr gut und liefert Codebeispiele.
Luis Perez

Antworten:


293

Wenn Sie eine Factory verwenden, ist Ihr Code weiterhin 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.


172
Das DI-Muster erfordert keine Frameworks. Sie können DI ausführen, indem Sie Fabriken, die DI ausführen, manuell schreiben. DI-Frameworks machen es einfach einfacher.
Esko Luontola

28
@Perpetualcoder - Danke @Esko - Lassen Sie sich nicht auf das Wort Framework ein, das eine erweiterte Bibliothek von Drittanbietern bedeutet.
Willcodejavaforfood

4
+1 @willcode danke! Sie müssen also stattdessen config / xml-Dateien ändern. Aha. Der Wiki-Link en.wikipedia.org/wiki/… definiert das Fabrikmuster alsManually-Injected Dependency
gideon

5
Ich habe nicht den Vorteil, eine XML-Zeile gegenüber einer Codezeile zu ändern. Könnten Sie näher darauf eingehen?
Rafael Eyng

1
Wiederholen Sie die OP-Antwort und ersetzen Sie "DI" durch "Factory". Dies ist immer noch sinnvoll.
Edson Medina

219

Ich würde vorschlagen, die Konzepte schlicht und einfach zu halten. Die Abhängigkeitsinjektion ist eher ein Architekturmuster für die lose Kopplung von Softwarekomponenten. Das Factory-Muster ist nur eine Möglichkeit, die Verantwortung für das Erstellen von Objekten anderer Klassen einer anderen Entität zu übertragen. Das Factory-Muster kann als Werkzeug zur Implementierung von DI aufgerufen werden. Die Abhängigkeitsinjektion kann auf viele Arten wie DI mithilfe von Konstruktoren, mithilfe von Mapping-XML-Dateien usw. implementiert werden.


4
Das ist richtig, dass Factory Pattern eine der Möglichkeiten ist, Dependency Injection zu implementieren. Ein weiterer Vorteil der Verwendung von Abhängigkeitsinjektion gegen Factory-Muster besteht darin, dass DI Frameworks Ihnen Flexibilität bei der Registrierung Ihrer Abstraktionen für Ihre konkreten Typen bieten. Wie Code wie Config, XML oder Auto Configuration. Durch diese Flexibilität können Sie die Lebensdauer Ihrer Objekte verwalten oder entscheiden, wie und wann Sie Ihre Schnittstellen registrieren möchten.
Teoman Shipahi

1
Das Factory-Muster bietet eine höhere Abstraktion als DI. Eine Fabrik kann Konfigurationsoptionen anbieten, genau wie DI, aber sie kann auch alle diese Konfigurationsdetails ausblenden, so dass die Fabrik entscheiden kann, zu einer völlig anderen Implementierung zu wechseln, ohne dass der Client dies weiß. DI alleine erlaubt dies nicht. DI verlangt vom Client, dass er die gewünschten Änderungen angibt.
Neuron

1
Gute Antwort. Viele verwechseln diese Frage: "Welche Muster soll ich wählen?" In der Tat sind Entwurfsmuster nur eine Möglichkeit, Probleme in geeigneten Situationen zu lösen. Wenn Sie nicht wissen, welches Entwurfsmuster Sie verwenden sollen, oder "Wo soll ich das Muster implementieren?" dann brauchst du das zu diesem Zeitpunkt nicht.
Benyi

2
Ich denke, es ist genauer zu sagen, dass Factory Pattern ein Werkzeug zur Implementierung von IoC (nicht DI) ist. Bitte beachten Sie, dass DI eine Form von IoC
Hooman Bahreini

185

Abhängigkeitsspritze

Anstatt die Teile selbst zu instanziieren, fragt ein Auto nach den Teilen, die es zum Funktionieren benötigt.

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

Fabrik

Fügt die Teile zu einem vollständigen Objekt zusammen und verbirgt den Betontyp vor dem Anrufer.

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 können, ergänzen sich Fabriken 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, um dasselbe 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 dadurch die Abhängigkeit vollständig ausgeblendet wird. Wenn Sie die Methode als Black Box betrachten würden, hätten Sie keine Ahnung, dass ein Auto erforderlich ist.

Beispiel 2 - Das ist etwas besser, weil wir jetzt wissen, dass wir ein Auto brauchen, da wir in einer Autofabrik vorbeikommen. Aber diesmal fahren wir zu viel vorbei, da die Methode eigentlich nur ein Auto benötigt. Wir fahren in einer Fabrik vorbei, um das Auto zu bauen, wenn das Auto außerhalb der Methode gebaut und übergeben werden könnte.

Beispiel 3 - Dies ist ideal, da die Methode genau das verlangt , was sie benötigt. Nicht zu viel oder zu wenig. Ich muss keine MockCarFactory schreiben, nur um MockCars zu erstellen, ich kann das Modell direkt übergeben. 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


1
Das Werksmuster wird als DI injiziert.
Mangesh Pimpalkar

7
@PhilGoetz Was Sie beschreiben, klingt eher nach dem Service Locator-Muster. Sie haben ähnliche Ziele, indem sie darauf abzielen, Dienstleistungen von ihren Verbrauchern zu entkoppeln. Das Service Locator-Muster weist jedoch viele Nachteile auf. Abhängig zu halten ist hauptsächlich keine gute Sache. Der Verbraucher muss noch seine Abhängigkeiten erhalten, aber anstatt eine klare Schnittstelle zu definieren, werden sie "heimlich" übergeben und verlassen sich auf den globalen Zustand. In dem Beispiel hat der Verbraucher keine Ahnung von der Fabrik, er fragt nur nach dem, was er benötigt, und muss sich nicht darum kümmern, wie dieser Bedarf aufgebaut ist.
Despertar

1
@MatthewWhited Die meisten Designentscheidungen haben einen Kompromiss. Mit DI erhalten Sie Flexibilität, Transparenz und ein besser testbares System, jedoch auf Kosten der Freilegung Ihrer Eingeweide. Viele Leute finden dies einen akzeptablen Kompromiss. Dies bedeutet nicht, dass DI immer die beste Lösung ist, und bei dieser Frage geht es nicht darum. Das Beispiel soll den Unterschied zwischen DI und Werksmuster zeigen, indem einige gute und schlechte Verwendungen von jedem gezeigt werden.
Despertar

3
Dies ist kein DI-Muster, sondern nur eine Implementierung von IoC. DI verwendet einen ServiceLocator, um die richtige Abhängigkeit zu ermitteln und sie während der Objekterstellung in den Konstruktor einzufügen. Ihr Code trennt nur die Erstellung von Objekten von Ihrem Klassenbereich.
Diego Mendes

3
@DiegoMendes Was Sie beschreiben, ist ein Framework, das DI automatisiert. Der ServiceLocator, wie Sie ihn nennen, erledigt den DI für Sie. Was ich zeige, ist das Muster selbst, das keine ausgefallenen Frameworks erfordert. Siehe stackoverflow.com/a/140655/1160036 oder en.wikipedia.org/wiki/… : "[Liste der Frameworks] unterstützt die Abhängigkeitsinjektion, muss jedoch keine Abhängigkeitsinjektion durchführen". "Eine Injektion ist das Übergeben einer Abhängigkeit an ein abhängiges Objekt". Sie sind damit fertig, ein wunderschön einfaches Konzept zu komplizieren.
Despertar

50

Der Grund, warum Dependency Injection (DI) und Factory Patterns ähnlich sind, liegt darin, dass es sich um zwei Implementierungen von Inversion of Control (IoC) handelt, einer Softwarearchitektur. Einfach ausgedrückt handelt es sich um 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 der Abhängigkeitsinjektion, wie der Name schon sagt, wird die Referenz in Ihren Code injiziert oder gegeben. Bei Factory-Mustern 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 Typ der vom Code verwendeten Objektreferenz.

Es ist erwähnenswert, dass Factory-Muster (oder tatsächlich Abstract Factory-Muster, bei denen es sich um Fabriken handelt, die neue Fabriken zurückgeben, die Objektreferenzen zurückgeben) geschrieben werden können, um den zur Laufzeit angeforderten Objekttyp oder die angeforderte Objektklasse dynamisch auszuwählen oder mit diesem zu verknüpfen. Dies macht sie dem Service Locator-Muster, das eine weitere Implementierung des IoC darstellt, sehr ähnlich (noch mehr als DI).

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

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


3
Dies ist die beste Antwort ... andere Antworten erwähnen entweder IoC nicht oder erkennen nicht, dass DI eine Form von IoC ist.
Hooman Bahreini

Danke, als ich das erste Mal IOC studierte, schrie ich fast, dass dies nur eine andere Form des Fabrikmusters war. Es stellte sich heraus, dass sie einander sehr ähnlich sind
Harvey Lin

40

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 einerseits der Inversion der Steuerung und der Abhängigkeitsinjektion (IOC / DI) und andererseits einem Service Locator oder einer Reihe von Fabriken (Fabrik) besteht in folgenden Punkten:

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 angeben. Ihre Domain - Objekte und Dienste werden von dem Behälter aufgebaut und konstruieren sich nicht: sie daher nicht über alle Abhängigkeiten auf den Behälter oder auf irgendwelchen Fabriken. IOC / DI ermöglicht ein extrem hohes Maß an Konfigurierbarkeit, wobei die gesamte Konfiguration an einem einzigen Ort (Aufbau des Containers) auf der obersten Ebene Ihrer Anwendung (der GUI, dem Web-Frontend) erfolgt.

Factory abstrahiert einen Teil der Konstruktion Ihrer Domain-Objekte und -Dienste. Domänenobjekte und -dienste sind jedoch weiterhin dafür verantwortlich, herauszufinden, wie sie sich selbst konstruieren und wie sie alle Dinge erhalten, von denen sie abhängen. Alle diese "aktiven" Abhängigkeiten filtern sich durch alle Ebenen Ihrer Anwendung. Es gibt keinen einzigen Ort, an dem Sie alles konfigurieren können.


26

Ein Nachteil von DI ist, dass es keine Objekte mit Logik initialisieren kann. Wenn ich beispielsweise ein Zeichen mit zufälligem Namen und Alter erstellen muss, ist DI nicht die Wahl gegenüber dem Fabrikmuster. Mit Fabriken können wir den Zufallsalgorithmus aus der Objekterstellung einfach kapseln, der eines der Entwurfsmuster unterstützt, das als "Verkapseln, was variiert" bezeichnet wird.


22

Das Lebenszyklusmanagement ist neben Instanziierung und Injektion eine der Aufgaben, die Abhängigkeitscontainer übernehmen. Die Tatsache, dass der Container nach der Instanziierung manchmal einen Verweis auf die Komponenten enthält, ist der Grund, warum er als "Container" und nicht als Fabrik bezeichnet wird. Abhängigkeitsinjektionsbehälter enthalten normalerweise nur einen Verweis auf Objekte, für die Lebenszyklen verwaltet werden müssen oder die für zukünftige Injektionen wie Singletons oder Fliehgewichte wiederverwendet werden. Bei der Konfiguration zum Erstellen neuer Instanzen einiger Komponenten für jeden Aufruf des Containers vergisst der Container normalerweise nur das erstellte Objekt.

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


15

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

Für ein Projekt mit einigen einfachen Typen, dessen Konstruktion eine relativ stabile Geschäftslogik erfordert, ist das Fabrikmuster offensichtlich einfach zu verstehen, zu implementieren und funktioniert gut.

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


14

Theorie

Es sind zwei wichtige Punkte zu beachten:

  1. Wer schafft Objekte

    • [Factory]: Sie müssen schreiben, wie ein Objekt erstellt werden soll. Sie haben eine separate Factory-Klasse, die die Erstellungslogik enthält.
    • [Abhängigkeitsinjektion]: In praktischen Fällen werden externe Frameworks verwendet (z. B. in Java wäre dies spring / ejb / guice). Die Injektion erfolgt "magisch", ohne dass explizit neue Objekte erstellt werden
  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 Abhängigkeitsinjektion in einem einzelnen Projekt

  1. Was wir bauen wollen

Anwendungsmodul zum Erstellen einer Bestellung, die mehrere Einträge enthält, die als Bestellposition bezeichnet werden.

  1. Die Architektur

Nehmen wir an, wir möchten folgende Ebenenarchitektur erstellen:

Geben Sie hier die Bildbeschreibung ein

Domänenobjekte können Objekte sein, die in der Datenbank gespeichert sind. Repository (DAO) hilft beim Abrufen von Objekten aus der Datenbank. Der Dienst stellt API für andere Module bereit. Ermöglicht Operationen am orderModul

  1. Domänenschicht und Nutzung von Fabriken

Entitäten, die sich in der Datenbank befinden, sind Order und OrderLine. Bestellung kann mehrere Bestellpositionen haben. Beziehung zwischen Order und OrderLine

Jetzt kommt wichtiger Designteil. Sollten Module außerhalb dieses Bereichs OrderLines selbst erstellen und verwalten? Nein. Die Bestellposition sollte nur vorhanden sein, wenn Sie eine Bestellung zugeordnet haben. Es ist am besten, wenn Sie die interne Implementierung für externe Klassen verbergen können.

Aber wie kann man eine Bestellung ohne Kenntnisse über OrderLines erstellen?

Fabrik

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

Geben Sie hier die Bildbeschreibung ein

So wird es in IDE aussehen. Klassen außerhalb des domainPakets werden OrderFactoryanstelle des Konstruktors innerhalb verwendetOrder

  1. Abhängigkeitsinjektion Die Abhängigkeitsinjektion wird häufiger bei zustandslosen Ebenen 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.

Geben Sie hier die Bildbeschreibung ein


Können Sie das bitte klarstellen? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsIch verstehe nicht warum
Maksim Dmitriev

2
Stateful-Objekte befinden sich wahrscheinlich in der Domänenanwendungsebene, in der Sie Ihre Daten einer Datenbank zuordnen. Dort verwenden Sie normalerweise keine Abhängigkeitsinjektion. Factory wird oft verwendet, um AggregateRoot aus einem Baum komplizierter Objekte zu erstellen
Marcin Szymczak

12

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

Ich denke, dass die Abhängigkeitsinjektion (DI) in vielerlei Hinsicht einem konfigurierbaren Factory Pattern (FP) ähnelt, und in diesem Sinne können Sie alles, was Sie mit DI tun können, mit einer solchen Factory tun.

Wenn Sie beispielsweise spring verwenden, haben Sie die Möglichkeit, Ressourcen automatisch zu verdrahten (DI) oder Folgendes zu tun:

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

Und dann verwenden Sie 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 einer anderen Klasse ist, und dass ein Framework als Factory funktioniert, aber ansonsten ist es dasselbe und Sie kann sicherlich eine Factory haben, die eine Konfigurationsdatei liest oder die Implementierung nach Bedarf erhält.

Und wenn Sie mich nach meiner Meinung fragen (und ich weiß, dass Sie es nicht getan haben), glaube ich, dass DI dasselbe tut, aber die Entwicklung nur komplexer macht, warum?

Zum einen müssen Sie zur Konfiguration selbst gehen, um zu wissen, welche Implementierung für jede Bean verwendet wird, die Sie automatisch mit DI verdrahten.

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

und zum einen spielt es keine Rolle, wie sehr Ihnen ein DI-Framework verspricht , dass Sie davon entkoppelte Dinge ohne Abhängigkeiten zu ihren Klassen erstellen. Wenn Sie ein Framework verwenden, erstellen Sie alles, was dazu gehört, wenn Sie müssen Ändern Sie den Ansatz oder den Rahmen, es wird keine leichte Aufgabe sein ... NIE! ... aber da Sie alles um dieses spezielle Framework herum aufbauen, anstatt sich Gedanken darüber zu machen, was die beste Lösung für Ihr Unternehmen ist, werden Sie dabei mit einem großen Problem konfrontiert sein.

Tatsächlich ist die einzige echte Geschäftsanwendung für einen FP- oder DI-Ansatz, die ich sehen kann, wenn Sie die zur Laufzeit verwendeten Implementierungen ändern müssen , aber zumindest die mir bekannten Frameworks erlauben Ihnen dies nicht. Sie müssen gehen Alles perfekt in der Konfiguration zur Entwicklungszeit und wenn Sie das brauchen, verwenden Sie einen anderen Ansatz.

Wenn ich also eine Klasse habe, die in zwei Bereichen in derselben Anwendung unterschiedliche Leistungen erbringt (z. B. zwei Unternehmen einer Holding), muss ich das Framework so konfigurieren, dass zwei verschiedene Beans erstellt werden, und meinen Code anpassen, um jeden zu verwenden. Ist das nicht dasselbe, 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, so etwas zu tun:

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

Und auf diese Weise legen Sie den Code der Fabrik fest, um zur Laufzeit die richtige Implementierung zu erhalten, abhängig vom Unternehmen des protokollierten Benutzers? Nun, das wäre hilfreich. Sie können einfach ein neues JAR mit den neuen Klassen hinzufügen und die Regeln möglicherweise auch 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 schreiben zu müssen und vielleicht sogar zwei verschiedene Anwendungen für jedes Unternehmen zu haben?

Sie können mir sagen, dass ich den Wechsel zur Laufzeit nie 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 kann man auch mit einer Fabrik machen. 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 diese werden solche Dinge tun. Aber hey, das kann man auch mit der Fabrik machen und wäre mit einer dynamischen Fabrik noch besser !!

Wie auch immer, der Kommentarbereich ist offen für dich, um mich zu töten.


3
Zu viele Entwickler glauben, dass Dependency Injection-Frameworks erstellt wurden, um etwas Neues zu bringen. Wie Sie gut erklären, können traditionelle Fabriken (meistens abstrakte Fabriken) die gleiche Rolle der Abhängigkeitsinversion spielen. Inversion vs Injektion? Für mich besteht der einzige "Vorteil" des Dependency Injection-Frameworks darin, dass wir den Code nicht ändern / neu kompilieren müssen (da er meistens mit XML wie Spring konfiguriert werden kann), wenn eine Abhängigkeit hinzugefügt / geändert wird. Warum vermeiden, neu zu kompilieren? Um mögliche menschliche Fehler beim Ändern der Abhängigkeit / Fabrik zu vermeiden. Aber mit unseren großartigen IDEs spielt Refactoring gut :)
Mik378

6

IOC ist ein Konzept, das auf zwei Arten umgesetzt wird. Abhängigkeitserstellung und Abhängigkeitsinjektion, Factory / Abstract Factory sind Beispiele für die Erstellung von Abhängigkeiten. Die Abhängigkeitsinjektion ist Konstruktor, Setter und Schnittstelle. Der Kern von IOC besteht darin, nicht von den konkreten Klassen abhängig zu sein, sondern die Zusammenfassung von Methoden (z. B. eine Schnittstelle / abstrakte Klasse) zu definieren und diese Zusammenfassung zu verwenden, um die Methode der konkreten Klasse aufzurufen. Geben Sie wie das Factory-Muster die Basisklasse oder Schnittstelle zurück. In ähnlicher Weise verwenden die Abhängigkeitsinjektion die Basisklasse / Schnittstelle, um den Wert für Objekte festzulegen.


4

Mit der Abhängigkeitsinjektion muss der Client seine Abhängigkeiten nicht selbst abrufen, sondern alles wird zuvor vorbereitet.

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 in Fabriken müssen Sie diese 1 Zeile überall dort schreiben, wo Sie ein solches Objekt benötigen. Mit DI müssen Sie die Verkabelung (Beziehung zwischen Nutzung und erstelltem Objekt) nur einmal erstellen und sich danach überall auf die Anwesenheit des Objekts verlassen. Auf der anderen Seite erfordert DI oft etwas mehr Arbeit (wie viel vom Framework abhängt) auf der Vorbereitungsseite.


3

Ich hatte die gleiche Frage, sobald ich über DI gelesen hatte und landete in diesem Beitrag. Schließlich habe ich das verstanden, aber bitte korrigieren Sie mich, wenn ich falsch liege.

"Vor langer Zeit gab es kleine Königreiche mit eigenen Leitungsgremien, die Entscheidungen auf der Grundlage ihrer eigenen schriftlichen Regeln kontrollierten und trafen. Später bildete sich eine große Regierung, die all diese kleinen Leitungsgremien beseitigte, die ein Regelwerk (Verfassung) haben und durch Gerichte umgesetzt werden."

Die Leitungsgremien der kleinen Königreiche sind "Fabriken".

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


1
WANN sieht man eine frühere kleine Regierung als groß an? In welchem ​​Maße?
Gefangener

3

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

Wenn sich die Anforderungen ändern, ändern Sie grundsätzlich mehr Code, wenn Sie Fabriken anstelle von DI verwenden.

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


3

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

Einmal hat mir jemand gesagt, dass es einen Unterschied macht, wie Sie es verwenden!

Genau. In 90% der Fälle können Sie die Objektreferenz entweder mit Factory oder DI erhalten, und normalerweise erhalten Sie letztere. In weiteren 10% der Fälle ist die Verwendung von Factory nur der richtige Weg . Diese Fälle umfassen das Abrufen von Objekten durch Variablen zu Laufzeitparametern. So was:

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

In diesem Fall clientist es nicht möglich , von DI zu kommen (oder erfordert zumindest eine hässliche Problemumgehung). Als allgemeine Regel für die Entscheidung: Wenn eine Abhängigkeit ohne berechnete Laufzeitparameter erhalten werden kann, wird DI bevorzugt, andernfalls verwenden Sie Factory.


2

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

Das Fabrikmuster ist nur eine andere Möglichkeit, Bohnen zu instanziieren. 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: Abhängigkeitsinjektion


2

Binoj,

Ich glaube nicht, dass Sie einen über den anderen wählen müssen.

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

Wann verwenden? Verwenden Sie das Muster oder die Muster in Ihrem Entwickler-Steuerhaus. Womit fühlen sie sich am wohlsten und finden es am einfachsten zu verstehen.


2

Ich glaube, 3 wichtige Aspekte bestimmen Objekte und ihre Verwendung:
1. Instanziierung (einer Klasse zusammen mit etwaiger Initialisierung).
2. Injektion (der so erstellten Instanz), wo es erforderlich ist.
3. Lebenszyklusmanagement (der so erstellten Instanz).

Unter Verwendung des Factory-Musters wird der erste Aspekt (Instanziierung) erreicht, die verbleibenden zwei sind jedoch fraglich. Die Klasse, die andere Instanzen verwendet, muss die Fabriken fest codieren (anstatt Instanzen zu erstellen), was lose Kopplungsfähigkeiten behindert. Außerdem, LebenszyklusmanagementDie Anzahl der Instanzen wird zu einer Herausforderung in einer großen Anwendung, in der eine Factory an mehreren Stellen verwendet wird (insbesondere wenn die Factory den Lebenszyklus der zurückgegebenen Instanz nicht verwaltet, wird sie hässlich). viel besser als Fabriken.

Bei Verwendung eines DI (mit IoC-Muster) werden andererseits alle 3 außerhalb des Codes (zum DI-Container) abstrahiert, und die verwaltete Bean benötigt nichts über diese Komplexität. Lose Kupplung , ein sehr wichtiges architektonisches Ziel, kann leise und bequem erreicht werden. Ein weiteres wichtiges architektonisches Ziel ist die Trennung von Anliegen

Während die Fabriken für kleine Anwendungen geeignet sind, ist es für große besser, DI gegenüber Fabriken zu wählen.


1

Meine Gedanken:

Abhängigkeitsinjektion: Ü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
Ja genau. Fast alle Erwähnungen von Dependency Injection (DI) in diesen Fragen und Antworten missbrauchen den Begriff im Gegensatz zu dieser Definition. Ein Dependency Injection Container (DIC) ist das am häufigsten verwendete Framework, das als generische und konfigurierbare Factory zum Erstellen von Objekten fungiert.
CXJ

1

Ein Injection Framework ist eine Implementierung des Factory-Musters.

Es hängt alles von Ihren Anforderungen ab. Wenn Sie das Factory-Muster 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 pflegen. Code ist eine Verbindlichkeit, kein Vermögenswert.

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


1

Factory Design Pattern

Das Werksmuster 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ängigkeitsspritze

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

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

  }
}

1

Von einem Nennwert aus sehen sie gleich aus

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

Aber ... "Das Rad nicht neu erfinden"

Aus architektonischer Sicht ist es eine Bindungsschicht und "Das Rad nicht neu erfinden".

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

Zusätzlich zu "GetType / Create" aus einer Factory benötigen wir meistens mehr Funktionen (Fähigkeit, XML zum Definieren von Abhängigkeiten, Verspotten und Testen von Einheiten usw. zu verwenden). Da Sie sich auf die Strukturkarte bezogen haben, sehen Sie sich die Funktionsliste der Strukturkarte an . 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 gibt (möglicherweise ein oder zwei) und nur wenige Abhängigkeiten aufweist, können Sie einen einfacheren Ansatz wählen. Es ist so, als würde man den ADO .Net-Datenzugriff über Entity Framework für einfache 1 oder 2 Datenbankaufrufe verwenden, 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

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 constructor overinjection, um diesen Code zu betrachten *):

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

Schauen Sie sich den Konstruktor an, Sie müssen nur die IAddressModelFactorydort ü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 CustomerControllervielen übergebenen Parametern: Ja, Sie können dies so sehen, constructor overinjectionaber so funktioniert DI. Und nein, nichts ist falsch mit dem CustomerController.

*) Code stammt von nopCommerce.


1

In einfachen Worten impliziert die Methode "Abhängigkeitsinjektion gegen Fabrik" einen Push-gegen-Pull-Mechanismus.

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

Schubmechanismus : 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, bei dem wie bei der Abhängigkeitsinjektion diese Verantwortung ausgelagert wird (allerdings auf Kosten einer undichten Abstraktion).


0

Ich denke, diese sind orthogonal und können zusammen verwendet werden. Lassen Sie mich Ihnen ein Beispiel zeigen, das mir kürzlich bei der Arbeit begegnet ist:

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

@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 müssen Instanzen nur Parentempfangen DepXwerden, um sie an den ChildKonstruktor zu übergeben. Probleme damit:

  1. Parenthat mehr Wissen Childals es sollte
  2. Parent hat mehr Mitarbeiter als es sollte
  3. Das Hinzufügen von Abhängigkeiten Childumfasst das ÄndernParent

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

  1. Es verbirgt alle außer den wahren Parametern der ChildKlasse, wie von gesehenParent
  2. Es enthält das Wissen zum Erstellen eines Child, das in der DI-Konfiguration zentralisiert werden kann.

Dies ist die vereinfachte ParentKlasse und die ChildFactoryKlasse:

@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

Sie verwenden die Abhängigkeitsinjektion, wenn Sie genau wissen, welche Art von Objekten Sie zu diesem Zeitpunkt benötigen. Während Sie im Falle eines Fabrikmusters nur den Prozess des Erstellens von Objekten an die Fabrik delegieren, sind Sie sich nicht sicher, welchen genauen Objekttyp Sie benötigen.


-1

Ich verwende beide , um eine Inversion Of Control-Strategie mit besserer Lesbarkeit für Entwickler zu erstellen, die sie nach mir warten müssen.

Ich verwende eine Factory, um meine verschiedenen Layer-Objekte (Business, Datenzugriff) zu erstellen.

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Ein anderer Entwickler wird dies sehen und beim Erstellen eines Business Layer-Objekts sucht er in BusinessFactory und Intellisense gibt dem Entwickler alle möglichen Business Layer zum Erstellen. Muss das Spiel nicht spielen, finde die Schnittstelle, die ich erstellen möchte.

Diese Struktur ist bereits Inversion Of Control. Ich bin nicht länger für die Erstellung des spezifischen Objekts verantwortlich. Sie müssen jedoch weiterhin die Abhängigkeitsinjektion sicherstellen, um Änderungen problemlos vornehmen zu können. Das Erstellen einer eigenen benutzerdefinierten Abhängigkeitsinjektion ist lächerlich, daher verwende ich Unity. Innerhalb von CreateCarBusiness () bitte ich Unity, aufzulösen, welche Klasse dazu gehört und welche Lebensdauer sie hat.

Meine Code Factory Dependency Injection-Struktur lautet also:

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

Jetzt habe ich den Vorteil von beiden. Mein Code ist auch für andere Entwickler besser lesbar als für die Bereiche meiner Objekte, die ich verwende, anstatt für die Konstruktorabhängigkeitsinjektion, die nur besagt, dass jedes Objekt verfügbar ist, wenn die Klasse erstellt wird.

Ich verwende dies, um meinen Datenbankdatenzugriff beim Erstellen von Komponententests auf eine benutzerdefinierte codierte Datenzugriffsebene zu ändern. Ich möchte nicht, dass meine Unit-Tests mit Datenbanken, Webservern, E-Mail-Servern usw. kommunizieren. Sie müssen meine Business-Schicht testen, da dort die Intelligenz liegt.


-4

Die Verwendung der Abhängigkeitsinjektion ist meiner Meinung nach viel besser, wenn Sie: 1. Ihren Code in einer kleinen Partition bereitstellen, da dies beim Entkoppeln eines großen Codes gut funktioniert. 2. Testbarkeit ist einer der Fälle, in denen DI in Ordnung ist, da Sie die nicht entkoppelten Objekte leicht verspotten können. Mit Hilfe von Schnittstellen können Sie jedes Objekt einfach verspotten und testen. 3. Sie können jeden Teil des Programms gleichzeitig überarbeiten, ohne den anderen Teil des Programms codieren zu müssen, da es lose entkoppelt ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.