Warum brauchen wir ein abstraktes Fabrikdesignmuster?

124

Der größte Teil der Definition lautet:

Eine abstrakte Factory bietet eine Schnittstelle zum Erstellen von Familien verwandter Objekte, ohne deren konkrete Klassen anzugeben

Was ist die Verwendung von Abstract Factory Pattern, um die Aufgabe durch Erstellen eines Objekts der konkreten Klasse selbst zu erreichen? Warum haben wir eine Factory-Methode, die Objekte der Concrete-Klasse erstellt?

Bitte geben Sie mir ein Beispiel aus dem wirklichen Leben, in dem ich abstractFactory-Muster implementieren muss.

Amit
quelle

Antworten:

219

Abstract Factory ist ein sehr zentrales Entwurfsmuster für Dependency Injection (DI). Hier ist eine Liste von Fragen zum Stapelüberlauf, bei denen die Anwendung von Abstract Factory als Lösung akzeptiert wurde .

Nach meinem besten Verständnis stellen diese Fragen echte Bedenken oder Probleme dar, die Menschen hatten, sodass Sie mit einigen Beispielen aus der Praxis beginnen sollten:

Mark Seemann
quelle
6
Alle diese Beispiele beschreiben das Factory-Methodenmuster, da alle eine einzige Produktschnittstelle zurückgeben. Keines davon ist ein abstraktes Fabrikmuster, da keines von ihnen eine Familie verwandter Produktschnittstellen erzeugt.
jaco0646
31
Im Interesse einer vollständigen Offenlegung hätte der Autor dieser Antwort klarstellen müssen, dass er auch der Autor jeder der verknüpften Antworten ist. Daher ist diese Liste KEINE repräsentative Stichprobe aus der SO-Community.
jaco0646
1
@ jaco0646 IIRC, das Factory-Methodenmuster ist eine Spezialisierung des Template-Methodenmusters , das auf Vererbung beruht. Ich kann mich jedoch irren, da ich gerade unterwegs bin und mein GoF-Buch nicht dabei habe. Was meinen Sie mit "keiner von ihnen produziert eine Familie verwandter Produktschnittstellen"?
Mark Seemann
1
Der einfachste Hinweis darauf, dass eine Fabrik nicht dem abstrakten Fabrikmuster entspricht, besteht darin, die abstrakten Produkte zu zählen, die die Fabrik produziert (ich habe den Begriff "Produktschnittstellen" anstelle von "abstrakten Produkten" verwendet, um eine Überbeanspruchung des Wortes "abstrakt" zu vermeiden). . Eine Fabrik, die ein einzelnes abstraktes Produkt produziert, kann keine abstrakte Fabrik sein, da Abstract Factory per Definition eine Familie verwandter Produkte produziert . Es ist wichtig zu beachten, dass sich diese Familie nicht auf unterschiedliche Implementierungen einer Schnittstelle bezieht, sondern auf Produkte mit unterschiedlichen verwandten Schnittstellen.
jaco0646
1
Hier ist ein Beispiel für oodesign.com/abstract-factory-pattern.html . Dafür wurde das abstrakte Fabrikmuster ursprünglich erstellt.
user2802557
23

Ein reales Beispiel für die Verwendung des Abstract Factory-Musters ist der Datenzugriff auf zwei verschiedene Datenquellen. Angenommen, Ihre Anwendung unterstützt verschiedene Datenspeicher. (zB eine SQL-Datenbank und eine XML-Datei). Sie haben zwei verschiedene Datenzugriffsschnittstellen, z. B. eine IReadableStoreund IWritableStoredie von Ihrer Anwendung erwarteten allgemeinen Methoden, unabhängig von der Art der verwendeten Datenquelle.

Welche Art von Datenquelle verwendet werden soll, sollte die Art und Weise, wie Client-Code seine Datenzugriffsklassen abruft, nicht ändern. Sie AbstractDataAccessFactorywissen, welcher Datenquellentyp konfiguriert ist, und stellen eine konkrete Factory für den Clientcode bereit , dh SqlDataAccessFactoryoder XmlDataAccessFactory. Diese konkreten Fabriken können die konkreten Implementierungen erstellen, z . B. SqlReadableStoreund SqlWriteableStore.

Die DbProviderFactory in .NET Framework ist ein Beispiel für dieses Muster.

Johannes Rudolph
quelle
18
Diese Antwort könnte das Muster der Factory-Methode oder der statischen Factory genau beschreiben, nicht jedoch das Muster der abstrakten Factory.
jaco0646
5

Wenn ich Sie richtig verstehe, ist die Frage, warum wir sowohl die Factory-Methode als auch die abstrakten Factory-Muster haben. Sie benötigen eine abstrakte Factory, wenn verschiedene polymorphe Klassen unterschiedliche Instanziierungsverfahren haben. Sie möchten, dass ein Modul Instanzen erstellt und verwendet, ohne Details zur Objektinitialisierung zu kennen. Beispiel: Sie möchten Java-Objekte erstellen, die einige Berechnungen durchführen. Einige von ihnen sind jedoch Teil der Anwendung, während der Bytecode anderer aus der Datenbank gelesen werden sollte. Auf der anderen Seite - warum brauchen wir eine Fabrikmethode? Stimmen Sie zu, dass diese abstrakte Fabrik sie überlappt. In einigen Fällen ist das Schreiben von Code jedoch viel weniger, da weniger Klassen und Schnittstellen das System leichter verständlich machen.

David Gruzman
quelle
3

Was ist die Verwendung von Abstract Factory Pattern, um die Aufgabe durch Erstellen eines Objekts der konkreten Klasse selbst zu erreichen? Warum haben wir eine Factory-Methode, die Objekte der Concrete-Klasse erstellt?

In Abwesenheit von Abstract Factory muss der Kunde Details zu konkreten Klassen kennen. Diese dichte Kupplung wurde mit der Abstract Factory entfernt .

Jetzt legt die Factory-Methode einen Vertrag offen, den der Kunde verwenden muss. Sie können Ihrer Fabrik weitere Produkte hinzufügen, indem Sie neue Produkte hinzufügen, die die von der Factory-Methode bereitgestellte Schnittstelle implementieren.

Beziehen Sie sich zum besseren Verständnis auf diese verwandten SE-Fragen:

Was ist der grundlegende Unterschied zwischen dem Factory- und dem Abstract Factory-Muster?

Absicht:

Stellen Sie eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte bereit, ohne deren konkrete Klassen anzugeben.

Sie können die Absicht, Struktur, Checkliste und Faustregeln des Abstract Factory- Musters aus diesem Artikel zur Quellenherstellung verstehen .

Checkliste:

  1. Entscheiden Sie, ob Plattformunabhängigkeit und Erstellungsdienste die aktuelle Schmerzquelle sind.
  2. Ordnen Sie eine Matrix aus Plattformen und Produkten zu .
  3. Definieren Sie eine Factory-Schnittstelle , die aus einer Factory-Methode pro Produkt besteht.
  4. Definieren Sie für jede Plattform eine vom Werk abgeleitete Klasse, die alle Verweise auf den neuen Operator enthält.
  5. Der Client sollte alle Verweise auf new zurückziehen und die Factory-Methoden verwenden , um die Produktobjekte zu erstellen .
Ravindra Babu
quelle
2

Abstrakte Fabriken eignen sich hervorragend zur Unterstützung mehrerer Plattformen und zur Vereinheitlichung Ihrer Codebasis. Angenommen, Sie haben ein großes Qt- oder GTK + - oder .NET / Mono-Programm, das Sie unter Windows, Linux und OSX ausführen möchten. Sie haben jedoch eine Funktion, die auf jeder Plattform unterschiedlich implementiert ist (möglicherweise über die Kernel32-API oder eine POSIX-Funktion).

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

Mit dieser Abstract Factory muss Ihre Benutzeroberfläche nichts über die aktuelle Plattform wissen.

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
Piedar
quelle
1
Ich verstehe nicht, wie unterscheidet sich dies von der Verwendung von Factory-Methoden zur Rückgabe eines abstrakten Typs, sodass der Client die Implementierungsdetails nicht kennt?
Kiwicomb123
1

Wenn Sie sich die Entwurfsmuster ansehen, können fast alle überflüssig gemacht werden. Aber welches Muster bedeutet einen häufig verwendeten Ansatz zur Lösung einer ähnlichen Art von Problemen? Ein Entwurfsmuster bietet Ihnen einen Ansatz oder eine Lösung auf Entwurfsebene für eine Reihe ähnlicher Entwurfsprobleme. Mithilfe von Entwurfsmustern können Sie Ihr Problem lösen und somit schneller liefern.

Kangkan
quelle
1

Wenn Sie sich vorstellen, dass Sie einen Code haben, der mit der Abstraktion funktioniert, sollten Sie Abstraktionen und keine konkreten Klassen erstellen.

Sie sollten immer gegen Abstraktionen arbeiten, da Sie den Code besser ändern können.

Dies ist ein gutes Beispiel: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

Pablo Castilla
quelle
1

Ich finde das Abstract Factory-Muster überbewertet.

Erstens kommt es nicht so oft vor, dass Sie eine Reihe miteinander verbundener Typen haben, die Sie instanziieren möchten.

Zweitens reicht normalerweise die von Schnittstellen bereitgestellte Indirektionsebene (Abstraktion) aus, wenn mit Abhängigkeitsinjektion gearbeitet wird.

Das typische Beispiel für WindowsGui vs MacGui vs ..., bei dem Sie einen WindowsButton, MacButton, WindowsScrollBar, MacScrollbar usw. haben, ist häufig einfacher zu implementieren, indem Sie konkrete Schaltflächen, Bildlaufleisten usw. mithilfe des Visitor- und / oder Interpreter-Musters definieren tatsächliches Verhalten.

Eljenso
quelle
Es gibt einen bestimmten Zweck dafür. Mit der Abhängigkeitsinjektion möchten Sie keine Service Locators weiter unten vom Composite Root. Stattdessen verwenden Sie eine injizierte abstrakte Fabrik.
Adam Tuliper - MSFT
2
Nun ... die Verwendung von Service Locator mit DI ist ein Anti-Muster. Eine abstrakte Factory ist die universelle Lösung, wenn aus Abhängigkeitswerten ABHÄNGIGKEITEN erstellt werden müssen.
TheMentor
1

Ich denke, es gibt einen Ort für abstrakte Fabrikmuster anstelle von einfachen Fabrikmustern an Orten, an denen Ihre Instanziierungen sehr kompliziert, zu kompliziert und hässlich für eine einzelne Fabrik und zu kompliziert für die Benutzeroberfläche sind.

Angenommen, dies ist eine Marke von TYPE_A, keine einzelne Klasse. Angenommen, es gibt eine Familie von 100 ähnlichen Klassen vom Typ A, und Sie müssen ein Objekt aus ihnen instanziieren. Stellen Sie sich vor, es sind detaillierte Informationen erforderlich, um aus einer Marke vieler ähnlicher Objekttypen das richtige Objekt zu machen. In dieser Objektentität müssen Sie genau wissen, welche Parameter zu optimieren sind und wie sie zu optimieren sind.

In der speziellen Fabrik für diese Marke werden wir sie differenzieren lassen und das genaue Objekt zum Instanziieren und auch zum Instanziieren erhalten. Wir werden wissen, dass aufgrund von Eingaben aus dem Netz (sagen wir, welche Farbe im Online-Shop verfügbar ist) und von anderen Anwendungen und Diensten, die im Hintergrund ausgeführt werden (Parameter, die der Benutzeroberfläche nicht bekannt sind).

Und vielleicht haben wir morgen eine andere Familie von Typ_B und Typ_C zum Instanziieren. Die Benutzeroberfläche hat also das "Wenn sonst", um zu wissen, ob der Benutzer einen "Typ_A", "Typ_B" oder "Typ_C" möchte - aber die Fabrikklassen entscheiden genau, welche Klasse aus dem Typ (aus der Familie) erstellt werden soll, und wie man es abstimmt - welche Werte auf seine Parameter eingestellt oder an seinen Auftragnehmer gesendet werden sollen. All dies - nach vielen Parametern, die der Benutzeroberfläche nicht bekannt sind. All dies wird für eine einzelne Fabrikklasse zu viel sein.

Udi Reshef
quelle
0

Um Ihre Frage direkt zu beantworten, können Sie wahrscheinlich ohne ein solches Entwurfsmuster davonkommen.

Bedenken Sie jedoch, dass sich die meisten Projekte in der realen Welt weiterentwickeln und Sie eine Art Erweiterbarkeit bereitstellen möchten, um Ihr Projekt zukunftssicher zu machen.

Aus eigener Erfahrung wird meistens eine Fabrik implementiert, und wenn das Projekt wächst, wird es in komplexere Entwurfsmuster wie eine abstrakte Fabrik umgewandelt.

BlueTrin
quelle
0

Es geht nur um Abhängigkeiten. Wenn Sie sich nicht für enge Kopplungen und Abhängigkeiten interessieren, brauchen Sie keine abstrakte Factory. Es ist jedoch wichtig, sobald Sie eine Anwendung schreiben, die gewartet werden muss.

Daniel
quelle
0

Angenommen, Sie erstellen ein Glas, und jemand anderes verwendet Ihr Glas und möchte ein neues konkretes Objekt in Ihrem Code verwenden. Wenn Sie keine abstrakte Factory verwenden, muss sie Ihren Code ändern oder Ihren Code überschreiben. Wenn Sie jedoch eine abstrakte Fabrik verwenden, kann sie eine Fabrik bereitstellen und an Ihren Code übergeben, und alles ist in Ordnung.

Verfeinerte Version: Betrachten Sie das folgende Szenario: Jemand anderes hat ein Framework geschrieben. Das Framework verwendet eine abstrakte Factory und einige konkrete Fabriken, um zur Laufzeit viele Objekte zu erstellen. So können Sie ganz einfach Ihre eigene Factory im vorhandenen Framework registrieren und Ihre eigenen Objekte erstellen. Das Framework ist für Änderungen geschlossen und aufgrund des abstrakten Factory-Musters immer noch leicht zu erweitern.

Adrian Liu
quelle
0

Dieses Muster ist besonders nützlich, wenn der Client nicht genau weiß, welchen Typ er erstellen soll. Angenommen, ein Showroom, der ausschließlich Mobiltelefone verkauft, erhält eine Abfrage für die von Samsung hergestellten Smartphones. Hier kennen wir nicht den genauen Objekttyp, der erstellt werden soll (vorausgesetzt, alle Informationen für ein Telefon sind in Form eines konkreten Objekts verpackt). Wir wissen jedoch, dass wir nach Smartphones suchen, die von Samsung hergestellt werden. Diese Informationen können tatsächlich verwendet werden, wenn unser Design eine abstrakte Factory-Implementierung aufweist.

Grundlegendes zum abstrakten Factory-Muster in C #

Amir Shabani
quelle
0

Ein reales Beispiel finden Sie im System.Data.Common-Namespace mit abstrakten Basisklassen wie DbConnection, DbCommand und DbDataAdapter, die von den .NET Framework-Datenanbietern wie System.Data.SqlClient und System.Data.OracleClient gemeinsam genutzt werden Ermöglichen Sie einem Entwickler, generischen Datenzugriffscode zu schreiben, der nicht von einem bestimmten Datenanbieter abhängt.

Die DbProviderFactories-Klasse bietet statische Methoden zum Erstellen einer DbProviderFactory-Instanz. Die Instanz gibt dann ein korrektes stark typisiertes Objekt zurück, das auf Providerinformationen und der zur Laufzeit angegebenen Verbindungszeichenfolge basiert.

Beispiel:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

Geben Sie hier die Bildbeschreibung ein

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

Beispiel-2 Geben Sie hier die Bildbeschreibung ein

Code Solution-Architektur Geben Sie hier die Bildbeschreibung ein

Konkrete Factory-Instanzen werden mithilfe der folgenden statischen Factory-Methode bereitgestellt

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}
Hemendr
quelle