Was sind die Unterschiede zwischen den Entwurfsmustern von Abstract Factory und Factory?


454

Ich weiß, dass es viele Posts über die Unterschiede zwischen diesen beiden Mustern gibt, aber es gibt einige Dinge, die ich nicht finden kann.

Nach dem, was ich gelesen habe, können Sie anhand des Factory-Methodenmusters definieren, wie ein einzelnes konkretes Produkt erstellt werden soll, die Implementierung jedoch vor dem Client ausgeblendet werden, da ein generisches Produkt angezeigt wird. Meine erste Frage betrifft die abstrakte Fabrik. Ist es seine Aufgabe, es Ihnen zu ermöglichen, Familien von konkreten Objekten in (die von der von Ihnen verwendeten Fabrik abhängen können) und nicht nur ein einzelnes konkretes Objekt zu erstellen? Gibt die abstrakte Factory nur ein sehr großes Objekt oder mehrere Objekte zurück, je nachdem, welche Methoden Sie aufrufen?

Meine letzten beiden Fragen beziehen sich auf ein einzelnes Zitat, das ich an zahlreichen Stellen nicht vollständig verstehen kann:

Ein Unterschied zwischen beiden besteht darin, dass beim Abstract-Factory-Muster eine Klasse die Verantwortung für die Objektinstanziierung über die Komposition an ein anderes Objekt delegiert, während das Factory-Methodenmuster die Vererbung verwendet und sich auf eine Unterklasse stützt, um die gewünschte Objektinstanziierung zu handhaben.

Ich verstehe, dass das Factory-Methodenmuster über eine Creator-Schnittstelle verfügt, über die der ConcreteCreator weiß, welches ConcreteProduct instanziiert werden soll. Bedeutet dies, dass die Verwendung der Vererbung zur Handhabung der Objektinstanziierung verwendet wird?

Wie genau delegiert das Abstract Factory-Muster in Bezug auf dieses Zitat die Verantwortung für die Objektinstanziierung über die Komposition an ein anderes Objekt? Was bedeutet das? Es sieht so aus, als ob das Abstract Factory-Muster in meinen Augen auch Vererbung verwendet, um den Konstruktionsprozess durchzuführen, aber andererseits lerne ich immer noch etwas über diese Muster.

Jede Hilfe, insbesondere bei der letzten Frage, wäre sehr dankbar.



Wenn Sie sehen, wie die Instanz aus Client-Sicht erstellt wurde, können Sie das Zitat besser verstehen.
Karthik Bose

@nawfal, die Antworten in diesem Thread sind schrecklich.
jaco0646

Antworten:


494

Der Unterschied zwischen den beiden

Der Hauptunterschied zwischen einer "Factory-Methode" und einer "abstrakten Factory" besteht darin, dass die Factory-Methode eine einzelne Methode ist und eine abstrakte Factory ein Objekt ist. Ich denke, viele Leute verwechseln diese beiden Begriffe und verwenden sie austauschbar. Ich erinnere mich, dass es mir schwer fiel, genau herauszufinden, was der Unterschied war, als ich sie lernte.

Da die Factory-Methode nur eine Methode ist, kann sie in einer Unterklasse überschrieben werden, daher die zweite Hälfte Ihres Angebots:

... das Factory-Methodenmuster verwendet die Vererbung und stützt sich auf eine Unterklasse, um die gewünschte Objektinstanziierung zu handhaben.

Das Zitat geht davon aus, dass ein Objekt hier seine eigene Factory-Methode aufruft . Daher wäre das einzige, was den Rückgabewert ändern könnte, eine Unterklasse.

Die abstrakte Factory ist ein Objekt, das mehrere Factory-Methoden enthält. Betrachten Sie die erste Hälfte Ihres Zitats:

... mit dem Abstract Factory-Muster delegiert eine Klasse die Verantwortung für die Objektinstanziierung über die Komposition an ein anderes Objekt ...

Sie sagen, dass es ein Objekt A gibt, das ein Foo-Objekt erstellen möchte. Anstatt das Foo-Objekt selbst zu erstellen (z. B. mit einer Factory-Methode), wird ein anderes Objekt (die abstrakte Factory) zum Erstellen des Foo-Objekts verwendet.

Codebeispiele

Um Ihnen den Unterschied zu zeigen, wird hier eine Factory-Methode verwendet:

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

Und hier ist eine abstrakte Fabrik im Einsatz:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

15
Dies ist eine großartige Erklärung. Aber was ist der wichtigste Teil, der unbeantwortet bleibt, und das heißt: wann man eines verwendet und wann das andere Muster?
Croraf

11
Ich bin mir nicht sicher, ob das richtig ist. Ziemlich sicher, dass die Factory-Methode ein Entwurfsmuster ist, das nach Factory-Methoden benannt ist, jedoch Klassenstruktur und Vererbung umfasst. Es ist keine einzige Methode.
Aviv Cohn

2
Ist es also richtig zu sagen: Die Factory-Methode kann eine Methode in allen regulären Klassen mit unterschiedlichen Zwecken sein. Aber die Abstract Factory ist eine Klasse / ein Objekt, das von einem Kunden verwendet wird und NUR für die Erstellung einiger Produkte in einer Familie verantwortlich ist?
Hieu Nguyen

Bedeutet Ihre Verwendung des Wortes "Super" in "SuperFoo" nur einen Sonderfall von Foo, oder bedeutet es tatsächlich Superklasse? Wie ich angenommen habe, muss es eine Unterklasse sein.
Dahui

@dahui Ja, es ist eine Unterklasse. Ich habe es geändert SpecialFoo, um klarer zu sein.
Tom Dalling

125

Abstract Factory erstellt eine Basisklasse mit abstrakten Methoden, die Methoden für die Objekte definieren, die erstellt werden sollen. Jede Factory-Klasse, die die Basisklasse ableitet, kann für jeden Objekttyp eine eigene Implementierung erstellen.

Geben Sie hier die Bildbeschreibung ein

Die Factory-Methode ist nur eine einfache Methode zum Erstellen von Objekten in einer Klasse. Es wird normalerweise im aggregierten Stamm hinzugefügt (Die OrderKlasse hat eine Methode namens CreateOrderLine)

Geben Sie hier die Bildbeschreibung ein

Abstrakte Fabrik

Im folgenden Beispiel entwerfen wir eine Schnittstelle, damit wir die Warteschlangenerstellung von einem Messagingsystem entkoppeln und daher Implementierungen für verschiedene Warteschlangensysteme erstellen können, ohne die Codebasis ändern zu müssen.

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

Fabrikmethode

Das Problem bei HTTP-Servern ist, dass wir für jede Anfrage immer eine Antwort benötigen.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

Ohne die Factory-Methode wären die Benutzer des HTTP-Servers (dh Programmierer) gezwungen, implementierungsspezifische Klassen zu verwenden, die den Zweck der IHttpRequestSchnittstelle zunichte machen.

Daher führen wir die Factory-Methode ein, damit auch die Erstellung der Antwortklasse abstrahiert wird.

Zusammenfassung

Der Unterschied besteht darin, dass der beabsichtigte Zweck der Klasse, die eine Factory-Methode enthält, nicht darin besteht, Objekte zu erstellen , während eine abstrakte Factory nur zum Erstellen von Objekten verwendet werden sollte.

Bei der Verwendung von Factory-Methoden ist Vorsicht geboten, da es beim Erstellen von Objekten leicht ist, das LSP ( Liskov Substitution-Prinzip ) zu brechen .


3
Warum brauchen wir ein konkretes Produkt?
Andrew S

60
Weil niemand in Ideen investieren will.
Jgauffin

4
Die Abstract Factory sollte mehr als nur Button()eine "Familie verwandter Produkte" schaffen. Das kanonische GoF-Beispiel erstellt beispielsweise ScrollBar()und Window(). Der Vorteil ist, dass die Abstract Factory ein gemeinsames Thema für mehrere Produkte durchsetzen kann.
jaco0646

Jaco hat recht. Beachten Sie, dass beide UML-Diagramme im Wesentlichen gleich sind (abgesehen davon, dass die UML von Abstract Factory falsch ist). In beiden Fällen ruft der Client eine Factory-Methode zum Erstellen eines einzelnen Produkts auf.
Cobby

1
@ Andrews: Um Ihre Frage zu beantworten. Wenn wir keine unterschiedlichen konkreten Produkte (Klassen) für dieselbe Abstraktion (Schnittstelle) benötigen, benötigen wir wahrscheinlich stattdessen das Builder-Muster und nicht das Factory-Muster. (besser spät als nie;))
jgauffin

95

Der Unterschied zwischen AbstractFactory- und Factory-Entwurfsmustern ist wie folgt:

  • Die Factory-Methode wird verwendet, um nur ein Produkt zu erstellen. Bei Abstract Factory geht es jedoch darum, Familien verwandter oder abhängiger Produkte zu erstellen .
  • Das Factory-Methodenmuster stellt dem Client eine Methode zum Erstellen des Objekts zur Verfügung, während im Fall von Abstract Factory eine Familie verwandter Objekte verfügbar gemacht wird, die aus diesen Factory-Methoden bestehen können.
  • Das Factory-Methodenmuster verbirgt die Konstruktion eines einzelnen Objekts, während Abstract Factory die Konstruktion einer Familie verwandter Objekte verbirgt. Abstrakte Fabriken werden normalerweise mit (einer Reihe von) Fabrikmethoden implementiert.
  • Zusammenfassung Das Factory- Muster verwendet Komposition, um die Verantwortung für das Erstellen eines Objekts an eine andere Klasse zu delegieren, während das Entwurfsmuster der Factory-Methode die Vererbung verwendet und zum Erstellen eines Objekts auf einer abgeleiteten Klasse oder Unterklasse basiert.
  • Die Idee hinter dem Factory-Methodenmuster ist, dass ein Client nicht weiß, welche konkreten Klassen zur Laufzeit erstellt werden müssen, sondern nur eine Klasse erhalten möchte, die die Aufgabe übernimmt, während das Abstract Factory- Muster ausgeführt wird Am besten geeignet, wenn Ihr System mehrere Produktfamilien erstellen muss oder Sie eine Produktbibliothek bereitstellen möchten, ohne die Implementierungsdetails offenzulegen.!

Implementierung des Factory-Methodenmusters: Factory-Methode UML

Implementierung des abstrakten Fabrikmusters:

Abstrakte Fabrik UML


13
Mmm, ich bin mir nicht sicher über das Abstract Factory Beispiel. Ich denke, dass die Formfabrik und die Farbfabrik dieselben Methoden implementieren sollten. Aber wenn ich recht habe, hat die Probe keinen Sinn.
Joaquin Iurchuk

4
Die Aufzählungszeichen sind korrekt; Beide Diagramme sind jedoch völlig falsch und sehr irreführend. In der folgenden Abbildung von @Trying finden Sie ein genaues Modell von Abstract Factory.
jaco0646

1
Ich muss zustimmen, dass die 2 Diagramme in der Tat sehr irreführend sind. Ich habe sie auf der Tutorialspoint-Website gesehen und um ehrlich zu sein, stimme ich ihnen nicht zu 100% zu. Die Beschreibungen sehen aber gut aus
SoftwareDeveloper

Das ist sehr irreführend.
diyoda_

Über 50 Upvotes und die Diagramme sind sehr falsch. Beweis, dass Sie vielen Antworten auf Entwurfsmuster auf SO nicht vertrauen können.
Fuhrmanator

27

Der Hauptunterschied zwischen Abstract Factory und Factory Method besteht darin, dass Abstract Factory von Composition implementiert wird . Die Factory-Methode wird jedoch durch Vererbung implementiert .

Ja, Sie haben das richtig gelesen: Der Hauptunterschied zwischen diesen beiden Mustern ist die alte Debatte zwischen Komposition und Vererbung .

UML-Diagramme finden Sie im Buch (GoF). Ich möchte Codebeispiele bereitstellen, da ich denke, dass die Kombination der Beispiele aus den beiden wichtigsten Antworten in diesem Thread eine bessere Demonstration ergibt als jede Antwort allein. Zusätzlich habe ich Terminologie aus dem Buch in Klassen- und Methodennamen verwendet.

Abstrakte Fabrik

  1. Der wichtigste Punkt, den Sie hier verstehen sollten, ist, dass die abstrakte Fabrik in den Client injiziert wird . Aus diesem Grund sagen wir, dass Abstract Factory von Composition implementiert wird. Oft würde ein Abhängigkeitsinjektionsframework diese Aufgabe ausführen. Für DI ist jedoch kein Framework erforderlich.
  2. Der zweite kritische Punkt ist, dass die konkreten Fabriken hier keine Implementierungen der Factory-Methode sind! Der Beispielcode für die Factory-Methode ist weiter unten dargestellt.
  3. Und schließlich ist der dritte zu beachtende Punkt die Beziehung zwischen den Produkten: in diesem Fall die Ausgangs- und Antwortwarteschlangen. Eine konkrete Fabrik produziert Azure-Warteschlangen, die andere MSMQ. Der GoF bezeichnet diese Produktbeziehung als "Familie" und es ist wichtig zu wissen, dass Familie in diesem Fall keine Klassenhierarchie bedeutet.
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

Fabrikmethode

  1. Der wichtigste Punkt hier zu begreifen ist , dass das ConcreteCreator ist der Kunde. Mit anderen Worten, der Client ist eine Unterklasse, deren übergeordnetes Element das definiert factoryMethod(). Aus diesem Grund sagen wir, dass die Factory-Methode durch Vererbung implementiert wird.
  2. Der zweite wichtige Punkt ist, sich daran zu erinnern, dass das Factory-Methodenmuster nichts anderes als eine Spezialisierung des Vorlagenmethodenmusters ist. Die beiden Muster haben eine identische Struktur. Sie unterscheiden sich nur im Zweck. Die Factory-Methode ist kreativ (sie erstellt etwas), während die Vorlagenmethode verhaltensbezogen ist (sie berechnet etwas).
  3. Und schließlich ist der dritte zu beachtende Punkt, dass die Creator(übergeordnete) Klasse ihre eigene aufruft factoryMethod(). Wenn wir anOperation()aus der übergeordneten Klasse entfernen und nur eine einzige Methode zurücklassen, ist dies nicht mehr das Factory-Methodenmuster. Mit anderen Worten, die Factory-Methode kann nicht mit weniger als zwei Methoden in der übergeordneten Klasse implementiert werden. und einer muss den anderen anrufen.
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

Sonstiges & Verschiedene Fabrikmuster

Beachten Sie, dass die GoF zwar zwei verschiedene Factory-Muster definiert, dies jedoch nicht die einzigen existierenden Factory-Muster sind. Sie sind nicht unbedingt die am häufigsten verwendeten Factory-Muster. Ein berühmtes drittes Beispiel ist Josh Blochs Static Factory Pattern von Effective Java. Das Head First Design Patterns-Buch enthält noch ein weiteres Muster, das sie Simple Factory nennen.

Gehen Sie nicht in die Falle, wenn Sie davon ausgehen, dass jedes Factory-Muster mit einem Muster aus dem GoF übereinstimmen muss.


3
Tolle und sehr klare Antwort basierend auf guten Beispielen, die besten in diesem Thema IMO.
Luke Duda

Tolle Erklärung. +1 für die Factory-Methode muss ihren abstrakten Factory-Methodenpunkt aufrufen. Mit diesem Punkt ist es sehr klar, ohne diesen Punkt zu verstehen: Wenn wir eine Factory-Methode haben, die nicht von ihr selbst aufgerufen wird, impliziert dies, dass sie von einer anderen Klasse verwendet wird, die sie zusammensetzt, und ihre Unterklassen werden injiziert, sie wird zu einer abstrakten Factory Der Unterschied wird weniger deutlich, wenn der Punkt, dass die abstrakte Factory-Methode von der Factory selbst aufgerufen werden muss, wie das Muster der Vorlagenmethode nicht verstanden wird
nits.kk

Noch eine Frage-Bemerkung. Sollte das factoryMethod()immer die protected Methode im "Factory Method" -Muster sein? (Ich denke ja)
Jaroslaw Fedoruk

1
@YaroslavFedoruk, das GoF-Buch erlaubt publicFactory-Methoden, und die Methode muss nicht einmal sein abstract; Der kritische Punkt ist jedoch, dass die Methode für die Vererbung vorgesehen ist und daher ( staticoder ) nicht entweder oder sein kann final. Ich habe die Methode gemacht protectedund abstracthier, um die (erforderliche) Erweiterbarkeit hervorzuheben.
jaco0646

@ nits.kk, Sie könnten an einer verwandten Antwort interessiert sein .
jaco0646

26

Abstract Factory ist eine Schnittstelle zum Erstellen verwandter Produkte, die Factory-Methode ist jedoch nur eine Methode. Abstract Factory kann mit mehreren Factory-Methoden implementiert werden.

Abstrakte Fabrik UML


10
Du hast bereits die gleiche Antwort gepostet hier . Wenn Sie der Meinung sind, dass diese Frage ähnlich ist, kennzeichnen Sie sie stattdessen als Duplikat.
Ja͢ck

11

Betrachten Sie dieses Beispiel zum leichteren Verständnis.

Was bieten Telekommunikationsunternehmen? Zum Beispiel Breitband, Telefonleitung und Mobilfunk, und Sie werden gebeten, eine Anwendung zu erstellen, um ihren Kunden ihre Produkte anzubieten.

Im Allgemeinen würden Sie hier die Produkte erstellen, dh Breitband, Telefonleitung und Mobiltelefon über Ihre Factory-Methode, bei der Sie wissen, welche Eigenschaften Sie für diese Produkte haben, und dies ist ziemlich einfach.

Jetzt möchte das Unternehmen seinen Kunden ein Bündel ihrer Produkte anbieten, dh Breitband, Telefonleitung und Mobiltelefon insgesamt, und hier kommt die Abstract Factory zum Spielen.

Abstract Factory ist mit anderen Worten die Zusammensetzung anderer Fabriken, die für die Herstellung ihrer eigenen Produkte verantwortlich sind, und Abstract Factory weiß, wie diese Produkte in Bezug auf ihre eigenen Verantwortlichkeiten aussagekräftiger platziert werden können.

In diesem Fall ist die BundleFactoryist die abstrakte Fabrik, BroadbandFactory, PhonelineFactoryund MobileFactoryist Factory. Zur weiteren Vereinfachung verfügen diese Fabriken über die Factory-Methode zur Initialisierung der einzelnen Produkte.

Siehe das folgende Codebeispiel:

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

Hoffe das hilft.


1
staticIn beiden GoF-Factory-Mustern gibt es keine Methoden. Das ist falsch.
jaco0646

5

Beispiel aus dem wirklichen Leben. (Leicht zu erinnern)

Fabrik

Stellen Sie sich vor, Sie bauen ein Haus und nähern sich einem Zimmermann für eine Tür. Sie geben das Maß für die Tür und Ihre Anforderungen an, und er wird eine Tür für Sie bauen. In diesem Fall ist der Schreiner eine Fabrik für Türen. Ihre Spezifikationen sind Eingaben für die Fabrik, und die Tür ist die Ausgabe oder das Produkt von der Fabrik.

Abstrakte Fabrik

Betrachten Sie nun das gleiche Beispiel der Tür. Sie können zu einem Schreiner gehen, oder Sie können zu einem Plastiktürgeschäft oder einem PVC-Geschäft gehen. Alle von ihnen sind Türfabriken. Abhängig von der Situation entscheiden Sie, an welche Art von Fabrik Sie sich wenden möchten. Dies ist wie eine abstrakte Fabrik.

Ich habe hier sowohl das Factory-Methodenmuster als auch das abstrakte Factory-Muster erklärt, indem ich sie nicht verwendet habe, um Probleme zu erklären, und dann Probleme mithilfe der obigen Muster https://github.com/vikramnagineni/Design-Patterns/tree/master gelöst habe


3

Lassen Sie uns klarstellen, dass wir im Produktionscode die meiste Zeit ein abstraktes Factory-Muster verwenden, da Klasse A mit Schnittstelle B programmiert ist. Und A Instanzen von B erstellen muss. A muss also ein Factory-Objekt haben, um Instanzen von B zu erzeugen A ist also nicht von einer konkreten Instanz von B abhängig. Ich hoffe, es hilft.


3

Verstehe die Unterschiede in den Motivationen:

Angenommen, Sie erstellen ein Tool, in dem Sie Objekte haben, und eine konkrete Implementierung der Wechselbeziehungen der Objekte. Da Sie Variationen in den Objekten vorhersehen, haben Sie eine Indirektion erstellt, indem Sie die Verantwortung für das Erstellen von Varianten der Objekte einem anderen Objekt zugewiesen haben ( wir nennen es abstrakte Factory ). Diese Abstraktion hat großen Nutzen, da Sie zukünftige Erweiterungen vorhersehen, die Varianten dieser Objekte benötigen.

Eine weitere faszinierende Motivation in diesem Gedankengang ist ein Fall, in dem jedes oder keines der Objekte aus der gesamten Gruppe eine entsprechende Variante aufweist. Unter bestimmten Bedingungen wird eine der Varianten verwendet, und in jedem Fall müssen alle Objekte dieselbe Variante haben. Dies ist möglicherweise etwas kontraintuitiv zu verstehen, da wir häufig der Meinung sind, dass der konkrete Implementierungscode niemals brechen sollte, solange die Varianten eines Objekts einem gemeinsamen einheitlichen Vertrag folgen ( Schnittstelle im weiteren Sinne ). Die faszinierende Tatsache hierbei ist, dass dies nicht immer der Fall ist, insbesondere wenn das erwartete Verhalten nicht durch einen Programmiervertrag modelliert werden kann.

Ein einfaches ( die Idee von GoF entlehnt ) ist eine beliebige GUI-Anwendung, beispielsweise ein virtueller Monitor, der das Erscheinungsbild von MS, Mac oder Fedora-Betriebssystemen emuliert. Wenn hier beispielsweise alle Widget-Objekte wie Fenster, Schaltflächen usw. eine MS-Variante haben, mit Ausnahme einer Bildlaufleiste, die von der MAC-Variante abgeleitet ist, schlägt der Zweck des Tools schlecht fehl.

Diese oben genannten Fälle bilden das Grundbedürfnis von Abstract Factory Pattern .

Stellen Sie sich andererseits vor, Sie schreiben ein Framework, damit viele Benutzer mithilfe Ihres Frameworks verschiedene Tools ( wie das in den obigen Beispielen ) erstellen können. Durch die Idee eines Frameworks müssen Sie dies nicht tun, obwohl Sie keine konkreten Objekte in Ihrer Logik verwenden konnten. Sie legen lieber Verträge auf hoher Ebene zwischen verschiedenen Objekten und deren Interaktion ab. Während Sie ( als Framework-Entwickler ) auf einer sehr abstrakten Ebene bleiben, ist jeder Builder des Tools gezwungen, Ihren Framework-Konstrukten zu folgen. Sie ( die Tool Builder ) können jedoch frei entscheiden, welches Objekt erstellt werden soll und wie alle von ihnen erstellten Objekte interagieren. Im Gegensatz zum vorherigen Fall ( von Abstract Factory Pattern ) sind Sie ( als Framework-Ersteller)) müssen in diesem Fall nicht mit konkreten Objekten arbeiten; und kann vielmehr auf der Vertragsebene der Objekte bleiben. Darüber hinaus haben Sie oder die Werkzeugbauer im Gegensatz zum zweiten Teil der vorherigen Motivationen nie die Situation, Objekte aus Varianten zu mischen. Während der Framework-Code auf Vertragsebene bleibt, ist jeder Tool-Builder ( aufgrund der Art des Falls selbst ) darauf beschränkt, seine eigenen Objekte zu verwenden. Die Objekterstellung wird in diesem Fall an jeden Implementierer delegiert, und Framework-Anbieter bieten lediglich einheitliche Methoden zum Erstellen und Zurückgeben von Objekten. Solche Methoden sind für Framework-Entwickler unumgänglich, um mit ihrem Code fortzufahren, und haben einen speziellen Namen namens Factory-Methode ( Factory Method Pattern für das zugrunde liegende Muster ).

Einige Anmerkungen:

  • Wenn Sie mit der 'Vorlagenmethode' vertraut sind, werden Sie feststellen, dass bei Programmen, die sich auf eine beliebige Form von Framework beziehen, häufig Factory-Methoden von Vorlagenmethoden aufgerufen werden. Im Gegensatz dazu sind Template-Methoden von Anwendungsprogrammen oft eine einfache Implementierung eines bestimmten Algorithmus und ohne Factory-Methoden.
  • Um die Vollständigkeit der Gedanken zu gewährleisten, kann ein Werkzeugbauer unter Verwendung des oben erwähnten Frameworks , wenn er innerhalb jeder Fabrikmethode ein Werkzeug baut, anstatt ein konkretes Objekt zu erstellen, die Verantwortung weiter an eine Zusammenfassung delegieren -Fabrikobjekt, vorausgesetzt, der Tool-Builder sieht Variationen der konkreten Objekte für zukünftige Erweiterungen vor.

Beispielcode:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

3
  1. Meine erste Frage betrifft die abstrakte Fabrik. Ist es seine Aufgabe, es Ihnen zu ermöglichen, Familien von konkreten Objekten in (die von der von Ihnen verwendeten Fabrik abhängen können) und nicht nur ein einzelnes konkretes Objekt zu erstellen?

Ja. Die Absicht von Abstract Factory ist:

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


  1. Gibt die abstrakte Factory nur ein sehr großes Objekt oder mehrere Objekte zurück, je nachdem, welche Methoden Sie aufrufen?

Im Idealfall sollte pro Objekt, das der Client aufruft, ein Objekt zurückgegeben werden.

  1. Ich verstehe, dass das Factory-Methodenmuster über eine Creator-Schnittstelle verfügt, über die der ConcreteCreator weiß, welches ConcreteProduct instanziiert werden soll. Bedeutet dies, dass die Verwendung der Vererbung zur Handhabung der Objektinstanziierung verwendet wird?

Ja. Die Factory-Methode verwendet die Vererbung.

  1. Zusammenfassung Factory-Muster delegieren die Verantwortung für die Objektinstanziierung über Komposition an ein anderes Objekt? Was bedeutet das?

AbstractFactory definiert eine FactoryMethod und ConcreteFactory ist für die Erstellung eines ConcreteProduct verantwortlich. Folgen Sie einfach dem Codebeispiel in diesem Artikel .

Weitere Details finden Sie in verwandten SE-Beiträgen:

Was ist der grundlegende Unterschied zwischen den Factory- und den Abstract Factory-Mustern?

Entwurfsmuster: Factory vs Factory-Methode vs Abstract Factory


3

Die Factory-Methode basiert auf der Vererbung: Die Objekterstellung wird an Unterklassen delegiert, die die Factory-Methode zum Erstellen von Objekten implementieren.

Zusammenfassung Factory basiert auf der Objektzusammensetzung: Die Objekterstellung wird in Methoden implementiert, die in der Factory-Oberfläche verfügbar gemacht werden.

Hochrangiges Diagramm des Fabrik- und des abstrakten Fabrikmusters,

Diagramm

Weitere Informationen zur Factory-Methode finden Sie in diesem Artikel .

Weitere Informationen zur Abstract Factory-Methode finden Sie in diesem Artikel .


2

Um es mit minimaler Schnittstelle sehr einfach zu machen & bitte konzentrieren Sie sich auf "// 1":

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

Hier wichtige Punkte: 1. Factory & AbstractFactory-Mechanismen müssen Vererbung verwenden (System.Object-> Byte, Float ...); Wenn Sie also eine Vererbung im Programm haben, ist Factory (Abstract Factory wäre höchstwahrscheinlich nicht vorhanden) bereits von Entwurf 2 vorhanden. Creator (MyFactory) kennt den konkreten Typ und gibt daher ein konkretes Objekt an den Aufrufer (Main) zurück. In abstrakter Fabrik wäre der Rückgabetyp eine Schnittstelle.

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

Wichtige Punkte: 1. Voraussetzung: Honda würde "Regular", "Sports" erstellen, aber Hero würde "DarkHorse", "Sports" und "Scooty" erstellen. 2. Warum zwei Schnittstellen? Eine für den Herstellertyp (IVehicleFactory) und eine für die Produktfabrik (IVehicle); Eine andere Möglichkeit, 2 Schnittstellen zu verstehen, ist die abstrakte Fabrik, bei der es darum geht, verwandte Objekte zu erstellen. 2. Der Haken ist, dass die Kinder der IVehicleFactory zurückkehren und IVehicle (anstelle von Beton in der Fabrik); so bekomme ich Elternvariable (IVehicle); Dann erstelle ich einen tatsächlichen konkreten Typ, indem ich CreateSingleVehicle aufrufe und dann das übergeordnete Objekt in das tatsächliche untergeordnete Objekt umwandle. Was würde passieren , wenn ich tun RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; Sie erhalten ApplicationException und deshalb benötigen wir eine generische abstrakte Factory, die ich bei Bedarf erläutern würde.



0

Ich würde Abstract Factory jederzeit gegenüber Factory Method bevorzugen. Aus dem obigen Beispiel von Tom Dalling (übrigens eine großartige Erklärung) können wir erkennen, dass Abstract Factory komponierbarer ist, da wir lediglich eine andere Factory an den Konstruktor übergeben müssen (hier verwendete Konstruktorabhängigkeitsinjektion). Für die Factory-Methode müssen wir jedoch eine neue Klasse einführen (mehr Dinge verwalten) und Unterklassen verwenden. Ziehen Sie Komposition immer der Vererbung vor.


0

Erlauben Sie mir, es genau auszudrücken. Die meisten Antworten wurden bereits erläutert und enthalten auch Diagramme und Beispiele. Meine Antwort wäre also nur ein Liner. Meine eigenen Worte: - „Das abstrakte Factory-Muster fügt die abstrakte Ebene über mehrere Implementierungen von Factory-Methoden hinzu. bedeutet, dass eine abstrakte Fabrik ein oder mehrere Muster einer Fabrikmethode enthält oder zusammensetzt.


Das ist nicht richtig. Dies ist das allzu häufige Missverständnis, dass Abstract Factory nichts anderes als eine Fabrik von Fabriken ist.
jaco0646

0

Viele der obigen Antworten bieten keine Codevergleiche zwischen dem Muster "Abstract Factory" und "Factory Method". Es folgt mein Versuch, es über Java zu erklären. Hoffe, es hilft jemandem, der eine einfache Erklärung braucht.

Wie GoF treffend sagt: Abstract Factory bietet eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte, ohne deren konkrete Klassen anzugeben.

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }

Das ist nicht richtig. Dieser Code implementiert das allzu häufige Missverständnis, dass Abstract Factory nichts anderes als eine Fabrik von Fabriken ist.
jaco0646

1
@ jaco0646 Ich glaube, dass im Factory-Methodenmuster der Fokus darauf liegt, nur ein konkretes Produkt aus FactoryImpl herauszuholen. Während in abstrakten Factory-Mustern die FactoryImpls für die Bereitstellung mehrerer ähnlicher / verwandter ConcreteProducts verantwortlich sind, für die die Factory-Schnittstelle einen Vertrag bereitstellt. ZooFactory ist also überhaupt keine Fabrik von Fabriken, wie Sie sagen, sondern nur eine Schnittstelle, deren Impls konkrete Produkte bereitstellen, die miteinander in Beziehung stehen. Fühlen Sie sich frei, mein Verständnis zu korrigieren, wenn Sie nicht einverstanden sind.
Jatin Shashoo

Bei der Factory-Methode liegt der Schwerpunkt auf der Vererbung über die Unterklassifizierung, da die Factory-Methode eine Spezialisierung des Musters der Vorlagenmethode ist. Die Antwort mit der höchsten Bewertung oben zeigt ein anständiges Codebeispiel.
jaco0646

@ jaco0646 1. Bedeutet dies, dass ich im obigen Beispiel anstelle von Schnittstellen für AnimalFactory und deren Bereitstellung eine Klasse hätte verwenden und die Methode createAnimal () in ihren Unterklassen überschreiben sollen: CowAnimalFactory, LionAnimalFactory usw. ?? 2. Was denken Sie über das Beispiel für ZooFactory?
Jatin Shashoo

Zur ersten Frage: ja. Zum zweiten habe ich meinem Thread meine eigene Antwort hinzugefügt, anstatt weiterhin jede einzelne Antwort zu kritisieren.
jaco0646
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.