576 Stimmen

Dependency Injection vs. Factory Pattern

Die meisten der Beispiele, die für die Verwendung von Dependency Injection angeführt werden, können wir auch mit dem Factory Pattern lösen. Es sieht so aus, als ob der Unterschied zwischen Dependency Injection und Factory bei der Verwendung/Entwicklung verschwommen oder dünn ist.

Jemand hat mir einmal gesagt, dass es darauf ankommt, wie man es benutzt!

Ich habe einmal StructureMap einen DI-Container, um ein Problem zu lösen. Später habe ich ihn so umgestaltet, dass er mit einer einfachen Fabrik funktioniert und die Verweise auf StructureMap entfernt.

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

27 Stimmen

Können sich diese beiden Ansätze nicht gegenseitig ergänzen, indem man Dependency Injection zur Injektion von Fabrikklassen verwendet?

21 Stimmen

Es wäre wirklich schön, wenn diese Frage mit einem Code beantwortet werden könnte! Ich sehe immer noch nicht, wie DI vorteilhaft/unterschiedlich von der Verwendung einer Fabrik für die Erstellung sein würde? Sie müssen nur diese eine Zeile in der Fabrikklasse ersetzen, um zu ändern, welches Objekt/Implementierung erstellt wird?

2 Stimmen

@gideon würde das nicht dazu führen, dass Sie Ihre Anwendung kompilieren müssen, oder zumindest das Modul, das die Fabrikklasse enthält?

324voto

willcodejavaforfood Punkte 41426

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.

197 Stimmen

Das DI-Muster erfordert keine Rahmenwerke. Sie können DI durchführen, indem Sie manuell Fabriken schreiben, die DI durchführen. DI-Frameworks machen es nur einfacher.

36 Stimmen

@Perpetualcoder - Danke @Esko - Lassen Sie sich nicht auf das Wort Framework ein, das eine fortgeschrittene Bibliothek eines Drittanbieters bedeutet.

0 Stimmen

Können Sie sagen, welche Vorteile es hat, DI die Verantwortung für die Erstellung zu übertragen? Im Falle der Factory-Methode müssen Sie nur eine Codezeile ändern, um die Implementierung zu ändern, die erstellt werden soll, oder?

246voto

Perpetualcoder Punkte 13291

Ich würde vorschlagen, die Konzepte klar und einfach zu halten. Dependency Injection ist eher ein Architekturmuster für die lose Kopplung von Softwarekomponenten. Das Factory-Muster ist nur eine Möglichkeit, die Verantwortung für die Erstellung von Objekten anderer Klassen auf eine andere Einheit zu übertragen. Das Factory-Pattern kann als ein Werkzeug zur Implementierung von DI bezeichnet werden. Dependency Injection kann auf viele Arten implementiert werden, wie z.B. DI mit Konstruktoren, mit Mapping-Xml-Dateien usw.

5 Stimmen

Es stimmt, dass das Factory Pattern eine der Möglichkeiten ist, Dependency Injection zu implementieren. Ein weiterer Vorteil von Dependency Injection gegenüber Factory Pattern ist, dass DI-Frameworks Ihnen Flexibilität bei der Registrierung Ihrer Abstraktionen gegenüber Ihren konkreten Typen bieten. Wie z.B. Code as Config, XML oder Auto Configuration. Mit dieser Flexibilität können Sie die Lebensdauer Ihrer Objekte verwalten oder entscheiden, wie und wann Sie Ihre Schnittstellen registrieren.

3 Stimmen

Das Factory-Muster bietet eine höhere Abstraktionsebene als DI. Eine Fabrik kann Konfigurationsoptionen anbieten, genau wie DI, aber sie kann auch all diese Konfigurationsdetails verbergen, so dass die Fabrik entscheiden kann, zu einer völlig anderen Implementierung zu wechseln, ohne dass der Kunde davon weiß. DI allein lässt dies nicht zu. DI erfordert, dass der Kunde die von ihm gewünschten Änderungen angibt.

1 Stimmen

Gute Antwort. Viele sind mit dieser Frage verwirrt: "Welche Patente soll ich wählen?" In der Tat sind Entwurfsmuster nur eine Möglichkeit, Probleme in bestimmten Situationen zu lösen. Wenn Sie nicht wissen, welches Entwurfsmuster Sie verwenden sollen, oder "Wo soll ich das Muster implementieren?

242voto

Despertar Punkte 20373

Injektion von Abhängigkeiten

Anstatt die Teile selbst zu instanziieren, wird ein Auto fragt für die Teile, die es zum Funktionieren braucht.

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 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 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, mit der Dependency Injection ist es so eine Sache. 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 - Das ist das Schlimmste, weil es die Abhängigkeit völlig verdeckt. Wenn Sie die Methode als Blackbox betrachten würden, wüssten Sie nicht, dass sie ein Auto benötigt.

Beispiel #2 - Das ist schon etwas besser, denn jetzt wissen wir, dass wir ein Auto brauchen, da wir in einer Autofabrik vorbeikommen. Aber dieses Mal übergeben wir zu viel, denn alles, was die Methode wirklich braucht, ist ein Auto. Wir übergeben eine Fabrik, nur um das Auto zu bauen, wenn das Auto auch außerhalb der Methode gebaut und übergeben werden könnte.

Beispiel #3 - Dies ist ideal, da die Methode folgende Fragen stellt genau was es braucht. Nicht zu viel und nicht zu wenig. Ich muss keine MockCarFactory schreiben, nur um MockCars zu erstellen, ich kann den Mock direkt übergeben. Es ist direkt und die Schnittstelle lügt nicht.

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

1 Stimmen

@FilipCordas Dies ist nur ein Beispiel für die korrekte Verwendung von DI und konzentriert sich daher auf die Methodenschnittstelle und nicht auf die Implementierung. ICar könnte ein Verschlüsselungsalgorithmus sein oder etwas, das Daten aufbewahrt. Dies sind nur zwei von Tausenden von Dingen, für die Sie vielleicht keine konkreten Klassen kodieren wollen. Wie bei allen Dingen gibt es auch bei DI Kompromisse, so dass man nach bestem Wissen und Gewissen entscheiden muss, wann die gewonnene Flexibilität die Umwege wert ist.

0 Stimmen

@Despertar Ja, das könnte es, tut es aber nicht. Mein Problem, wenn ich über DI spreche, ist, dass die Leute so tun, als ob es alle Probleme in jeder Situation lösen würde, auch wenn es bessere Lösungen für die gleiche Situation gäbe, wie in dem Beispiel, das du genannt hast. Und das ServiceLocator-Muster ist kein DI-Muster, beide sind IOC-Muster, aber die beiden sind unterschiedlich.

84voto

Tom Maher Punkte 1724

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, also einer Softwarearchitektur. Einfach ausgedrückt sind sie zwei Lösungen für dasselbe Problem.

Um die Frage zu beantworten: Der Hauptunterschied zwischen dem Factory-Muster und DI besteht darin, wie die Objektreferenz erhalten wird. Bei der Dependency Injection wird, wie der Name schon sagt, der Verweis in den Code injiziert oder gegeben. Beim Factory-Muster muss Ihr Code die Referenz anfordern, damit Ihr Code das Objekt abruft. Bei beiden Implementierungen wird die Verknüpfung zwischen dem Code und der zugrundeliegenden Klasse oder dem Typ des Objektverweises, der vom Code verwendet wird, entfernt oder entkoppelt.

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

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

Ich schätze, wenn es um IoC-Entwurfsmuster geht: Injektoren sind Injektoren, Locatoren sind Locatoren und die Fabriken wurden refaktorisiert.

8 Stimmen

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

0 Stimmen

Danke, als ich zum ersten Mal IOC studierte, hätte ich fast geschrien, dass dies nur eine andere Form des Fabrikmusters sei, aber es stellte sich heraus, dass sie einander sehr ähnlich sind

0 Stimmen

Tom, ich möchte meinen Kopf frei bekommen und bin gekommen, um eine Frage zu stellen, aber da sie bereits gestellt wurde. Ich bin der Meinung, dass ich, anstatt FP zu verwenden und mir Sorgen um FP zu machen, DI fast die ganze Zeit verwenden kann, um die Klassen zu entkoppeln und das Open/Close-Prinzip zu erreichen. Was ich mit der Serviceklasse in DI erreichen kann, könnte ich auch mit FP erreichen, aber ich werde den DI-Ansatz wählen, weil ich einige Beispiele gesehen habe, in denen das Factory-Pattern implementiert wurde, aber auch DI wurde oben drauf mit ServiceCollection implementiert, die IServiceProvider oder manuell erstellte Services zurückgibt. Warum sich also mit FP abmühen. Was denken Sie?

40voto

yfeldblum Punkte 64211

Es gibt Probleme, die mit Dependency Injection leicht zu lösen sind, die mit einer Reihe von Factories nicht so leicht zu lösen sind.

Der Unterschied zwischen der Umkehrung der Kontrolle und der Injektion von Abhängigkeiten (IOC/DI) einerseits und einem Service-Locator oder einer Reihe von Fabriken (Factory) andererseits besteht unter anderem darin, dass es sich dabei um eine Kombination aus zwei Komponenten handelt:

IOC/DI ist ein vollständiges Ökosystem von Domänenobjekten und -diensten in sich selbst. Es richtet alles für Sie so ein, wie Sie es angeben. Ihre Domänenobjekte und -dienste werden durch den Container konstruiert und konstruieren sich nicht selbst: Sie haben daher keine cualquier Abhängigkeiten vom Container oder von irgendwelchen Fabriken. IOC/DI ermöglicht ein extrem hohes Maß an Konfigurierbarkeit, wobei die gesamte Konfiguration an einer einzigen Stelle (Konstruktion des Containers) auf der obersten Schicht Ihrer Anwendung (der grafischen Benutzeroberfläche, dem Web-Frontend) erfolgt.

Factory abstrahiert einen Teil der Konstruktion Ihrer Domänenobjekte und -dienste. Aber die Domänenobjekte und -dienste sind immer noch dafür verantwortlich, herauszufinden, wie sie sich selbst konstruieren und wie sie all die Dinge erhalten, von denen sie abhängig sind. All diese "aktiven" Abhängigkeiten ziehen sich durch alle Schichten Ihrer Anwendung hindurch. Es gibt keinen einzigen Ort, an dem man alles konfigurieren kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X