Was ist der Unterschied zwischen dem Builder-Entwurfsmuster und dem Factory-Entwurfsmuster?


661

Was ist der Unterschied zwischen dem Builder-Entwurfsmuster und dem Factory-Entwurfsmuster?

Welches ist vorteilhafter und warum?

Wie stelle ich meine Ergebnisse als Grafik dar, wenn ich diese Muster testen und vergleichen / kontrastieren möchte?


12
Was meinst du mit "vorteilhaft", da sie verschiedene Dinge tun?
S.Lott

5
Builder ist eine komplexere Version des Konstruktors - während die Factory-Methode vereinfacht ist.
Dávid Horváth

@ DávidHorváth Ich würde einen Builder nicht als "komplexer" bezeichnen. Wenn Sie mit einem Konstruktor mit 100 Parametern arbeiten und sich nur um 3 davon kümmern und wissen, dass sich die Anzahl der Parameter in Zukunft möglicherweise ändern wird, würde die Verwendung des Builder-Musters das Leben aller erheblich vereinfachen.
Aberrant

@Aberrant Komplizierte Nutzung und architektonische Komplexität sind zwei verschiedene Dinge. Ich habe mich auf Letzteres konzentriert.
Dávid Horváth

Antworten:


466

Bei Entwurfsmustern gibt es normalerweise keine "vorteilhaftere" Lösung, die für alle Fälle funktioniert. Dies hängt davon ab, was Sie implementieren müssen.

Aus Wikipedia:

  • Builder konzentriert sich darauf, Schritt für Schritt ein komplexes Objekt zu erstellen. Abstract Factory betont eine Familie von Produktobjekten (entweder einfach oder komplex). Builder gibt das Produkt als letzten Schritt zurück, aber in Bezug auf die Abstract Factory wird das Produkt sofort zurückgegeben.
  • Builder erstellt häufig ein Composite.
  • Entwürfe beginnen häufig mit der Factory-Methode (weniger kompliziert, anpassbarer, Unterklassen vermehren sich) und entwickeln sich zu Abstract Factory, Prototype oder Builder (flexibler, komplexer), wenn der Designer feststellt, wo mehr Flexibilität erforderlich ist.
  • Manchmal ergänzen sich Kreationsmuster: Builder kann eines der anderen Muster verwenden, um zu implementieren, welche Komponenten erstellt werden. Abstract Factory, Builder und Prototype können Singleton in ihren Implementierungen verwenden.

Wikipedia-Eintrag für das Factory-Design-Muster: http://en.wikipedia.org/wiki/Factory_method_pattern

Wikipedia-Eintrag für das Builder-Entwurfsmuster: http://en.wikipedia.org/wiki/Builder_pattern


159
Das ist genau der Unterschied. Der Builder wird nur benötigt, wenn ein Objekt nicht in einem Schritt erstellt werden kann. Ein gutes Beispiel hierfür wäre der De-Serialisierungsprozess für ein komplexes Objekt. Oft müssen die Parameter für das komplexe Objekt einzeln abgerufen werden.
Bernard Igiri

1
Für den ersten Satz würde ich sagen, dass es absolut oft eine vorteilhaftere Lösung gibt, die allgemein gilt ... wir sehen diese einfach nicht, weil sie direkt in Programmiersprachen gebacken werden.
Joel Coehoorn

4
@Joel: Ich stimme zu, dass einige Muster häufiger sind als andere (zum Beispiel scheint Factory häufiger zu sein als Builder), aber ich meinte, dass keines von ihnen immer besser ist als das andere, egal wie das Szenario aussieht .
Adrian Grigore

@AdrianGrigore was ist, wenn beide mischen? Aso.net mvc haben ControllerBuilder, die die Methode für die ControllerFactory-Klasse festgelegt und abgerufen haben
AminM

Gute Antwort, obwohl zwei Dinge, die hinzugefügt werden sollten, sind: 1) Builder wird hauptsächlich zum Erstellen von POJOs mithilfe der Fluent-API verwendet (z. B. Person.builder (). WithName ("Sam"). WithAge (38) .build (). 2) Nach meiner Erfahrung ist der Builder nützlich für die POJO-Erstellung für Domänenobjekte, während die Factory für die Erstellung von Serviceobjekten wie der PdfGeneratorFactory-Klasse nützlich ist. Das Serviceobjekt kann innerhalb der Factory mehr als einmal zwischengespeichert werden, während der Builder immer ein neues Objekt erstellt.
saurabh.in

357

Eine Factory ist einfach eine Wrapper-Funktion um einen Konstruktor (möglicherweise eine in einer anderen Klasse). Der Hauptunterschied besteht darin, dass für ein Factory-Methodenmuster das gesamte Objekt in einem einzigen Methodenaufruf erstellt werden muss, wobei alle Parameter in einer einzigen Zeile übergeben werden. Das endgültige Objekt wird zurückgegeben.

Ein Builder-Muster ist im Wesentlichen ein Wrapper-Objekt um alle möglichen Parameter, die Sie möglicherweise an einen Konstruktoraufruf übergeben möchten. Auf diese Weise können Sie Setter-Methoden verwenden, um Ihre Parameterliste langsam aufzubauen. Eine zusätzliche Methode für eine Builder-Klasse ist eine build () -Methode, die das Builder-Objekt einfach an den gewünschten Konstruktor übergibt und das Ergebnis zurückgibt.

In statischen Sprachen wie Java wird dies wichtiger, wenn Sie über mehr als eine Handvoll (möglicherweise optionaler) Parameter verfügen, da keine Teleskopkonstruktoren für alle möglichen Kombinationen von Parametern erforderlich sind. Mit einem Builder können Sie auch Setter-Methoden verwenden, um schreibgeschützte oder private Felder zu definieren, die nach dem Aufruf des Konstruktors nicht direkt geändert werden können.

Grundlegendes Fabrikbeispiel

// Factory
static class FruitFactory {
    static Fruit create(name, color, firmness) {
        // Additional logic
        return new Fruit(name, color, firmness);
    }
}

// Usage
Fruit fruit = FruitFactory.create("apple", "red", "crunchy");

Beispiel für einen einfachen Builder

// Builder
class FruitBuilder {
    String name, color, firmness;
    FruitBuilder setName(name)         { this.name     = name;     return this; }
    FruitBuilder setColor(color)       { this.color    = color;    return this; }
    FruitBuilder setFirmness(firmness) { this.firmness = firmness; return this; }
    Fruit build() {
        return new Fruit(this); // Pass in the builder
    }
}

// Usage
Fruit fruit = new FruitBuilder()
        .setName("apple")
        .setColor("red")
        .setFirmness("crunchy")
        .build();

Es kann sich lohnen, die Codebeispiele dieser beiden Wikipedia-Seiten zu vergleichen:

http://en.wikipedia.org/wiki/Factory_method_pattern
http://en.wikipedia.org/wiki/Builder_pattern


1
Das ist nicht die richtige Verwendung von Builder Pattern Imo, selbst in dem Wiki-Link, den Sie verwendet haben, ist die Verwendung anders. Dieser FruitBuilder ist eine Mischung aus Director- und Builder-Komponente, in der Sie build () aufrufen, das Director gehören sollte, und Setter, die zur Builder-Komponente gehören. Director sollte Geschäftslogik zum Erstellen von Objekten mit Builders-Methoden enthalten. Fließende Apis sind keine Builder-Muster und StringBuilder ist auch kein Builder-Muster.
Kmaczek

281

Das Factory-Muster kann fast als vereinfachte Version des Builder-Musters angesehen werden.

In der Fabrik Muster ist die Factory dafür verantwortlich, je nach Bedarf verschiedene Untertypen eines Objekts zu erstellen.

Der Benutzer einer Factory-Methode muss den genauen Subtyp dieses Objekts nicht kennen. Ein Beispiel für eine Factory-Methode createCarkönnte a Fordoder a zurückgebenHonda typisiertes Objekt zurückgeben.

Im Builder- Muster werden auch verschiedene Untertypen von einer Builder-Methode erstellt, die Zusammensetzung der Objekte kann jedoch innerhalb derselben Unterklasse unterschiedlich sein.

Um das Auto-Beispiel fortzusetzen, haben Sie möglicherweise eine createCarBuilder-Methode, die ein HondaObjekt vom Typ mit einem 4-Zylinder-Motor erstellt, oder aHonda Objekt vom Typ mit 6 Zylindern erstellt. Das Builder-Muster ermöglicht diese feinere Granularität.

Diagramme sowohl des Builder-Musters als auch des Factory-Methodenmusters sind auf Wikipedia verfügbar.


13
Das Builder-Muster ist wie das Vergrößern der Konstruktion des großen Objekts. Das große Objekt besteht aus einem anderen Objekt, das sich wie eine Rekursion weiter zusammensetzt. Während Fabrik bekommt Sie nur das Ding in einem Anruf. Ist dieses Verständnis richtig?
Fooo

63

Das Builder-Entwurfsmuster beschreibt ein Objekt, das in mehreren Schritten ein anderes Objekt eines bestimmten Typs erstellen kann. Es enthält den erforderlichen Status für das Zielobjekt bei jedem Zwischenschritt. Überlegen Sie, was StringBuilder durchläuft, um eine endgültige Zeichenfolge zu erstellen.

Das Factory-Entwurfsmuster beschreibt ein Objekt, das in einem Schritt mehrere verschiedene, aber verwandte Objekttypen erstellen kann, wobei der spezifische Typ anhand der angegebenen Parameter ausgewählt wird. Stellen Sie sich das Serialisierungssystem vor, in dem Sie Ihren Serializer erstellen und das gewünschte Objekt in einem einzigen Ladeaufruf erstellen.


7
Nur ein Hinweis: Ein gutes Beispiel für das Builder-Muster ist "Fluent Interface" und ADO.NET ist voll mit "Factory" - und "Abstract Factory" -Implementierungen (dh DbFactory).
Boj

50
  • Schritt für Schritt ein komplexes Objekt erstellen: Builder-Muster

  • Ein einfaches Objekt wird mit einer einzigen Methode erstellt: dem Factory-Methodenmuster

  • Erstellen eines Objekts mithilfe mehrerer Factory-Methoden: Abstraktes Factory-Muster


21

Builder Pattern und Factory Pattern scheinen beide bloßen Augen ziemlich ähnlich zu sein, da sie beide Objekte für Sie erstellen.

Aber du musst genauer hinsehen

Dieses Beispiel aus dem wirklichen Leben wird den Unterschied zwischen den beiden deutlicher machen.

Angenommen, Sie ging zu einem Fast - Food - Restaurant und bestellten Essen .

1) Welches Essen?

Pizza

2) Welche Beläge?

Capsicum, Tomate, BBQ Huhn, keine Ananas

So werden verschiedene Arten von Lebensmitteln nach dem Factory-Muster hergestellt, aber die verschiedenen Varianten (Aromen) eines bestimmten Lebensmittels werden nach dem Builder-Muster hergestellt.

Verschiedene Arten von Lebensmitteln

Pizza, Burger, Pasta

Varianten der Pizza

Nur Käse, Käse + Tomaten + Paprika, Käse + Tomaten usw.

Codebeispiel

Sie können die Beispielcode-Implementierung beider Muster hier sehen.
Builder Pattern
Factory Pattern


1
Vielen Dank für die Bereitstellung des Beispielcodes! Ihre Beispiele unterscheiden diese beiden Muster sehr gut.
Rommel Paras

18

Beide sind Schöpfungsmuster, um ein Objekt zu erstellen.

1) Factory Pattern - Angenommen, Sie haben eine Superklasse und N Unterklassen. Das erstellte Objekt hängt davon ab, welcher Parameter / Wert übergeben wird.

2) Builder-Muster - um ein komplexes Objekt zu erstellen.

Ex: Make a Loan Object. Loan could be house loan, car loan ,
    education loan ..etc. Each loan will have different interest rate, amount ,  
    duration ...etc. Finally a complex object created through step by step process.

12

Zunächst einige allgemeine Dinge, die meiner Argumentation folgen sollen:

Die größte Herausforderung beim Entwurf großer Softwaresysteme besteht darin, dass sie flexibel und unkompliziert sein müssen, um Änderungen vorzunehmen. Aus diesem Grund gibt es einige Metriken wie Kopplung und Kohäsion. Um Systeme zu erhalten, deren Funktionalität leicht geändert oder erweitert werden kann, ohne dass das gesamte System von Grund auf neu entworfen werden muss, können Sie den Entwurfsprinzipien (wie SOLID usw.) folgen. Nach einer Weile erkannten einige Entwickler, dass es ähnliche Lösungen gibt, die bei ähnlichen Problemen gut funktionieren, wenn sie diesen Prinzipien folgen. Diese Standardlösungen erwiesen sich als Entwurfsmuster.

Die Entwurfsmuster sollen Sie also dabei unterstützen, die allgemeinen Entwurfsprinzipien zu befolgen, um lose gekoppelte Systeme mit hoher Kohäsion zu erzielen.

Beantwortung der Frage:

Wenn Sie nach dem Unterschied zwischen zwei Mustern fragen, müssen Sie sich fragen, welches Muster Ihr System auf welche Weise flexibler macht. Jedes Muster hat seinen eigenen Zweck, Abhängigkeiten zwischen Klassen in Ihrem System zu organisieren.

Das abstrakte Factory-Muster: GoF: „Stellen Sie eine Schnittstelle zum Erstellen von Familien verwandter oder abhängiger Objekte bereit, ohne deren konkrete Klassen anzugeben.“

Was bedeutet das? Durch die Bereitstellung einer solchen Schnittstelle wird der Aufruf des Konstruktors für jedes Produkt der Familie in der Factory-Klasse gekapselt. Und da dies der einzige Ort in Ihrem gesamten System ist, an dem diese Konstruktoren aufgerufen werden, können Sie Ihr System ändern, indem Sie eine neue Factory-Klasse implementieren. Wenn Sie die Darstellung der Fabrik durch eine andere austauschen, können Sie eine ganze Reihe von Produkten austauschen, ohne den größten Teil Ihres Codes zu berühren.

Das Builder-Muster: GoF: „Trennen Sie die Konstruktion eines komplexen Objekts von seiner Darstellung, damit derselbe Konstruktionsprozess unterschiedliche Darstellungen erstellen kann.“

Was bedeutet das ? Sie kapseln den Konstruktionsprozess in einer anderen Klasse, dem Director (GoF). Dieser Director enthält den Algorithmus zum Erstellen neuer Instanzen des Produkts (z. B. Erstellen eines komplexen Produkts aus anderen Teilen). Um die integralen Bestandteile des gesamten Produkts zu erstellen, verwendet der Director einen Builder. Durch Austauschen des Builders im Director können Sie denselben Algorithmus zum Erstellen des Produkts verwenden, jedoch die Darstellungen einzelner Teile (und damit die Darstellung des Produkts) ändern. Um Ihr System in der Darstellung des Produkts zu erweitern oder zu ändern, müssen Sie lediglich eine neue Builder-Klasse implementieren.

Kurz gesagt: Der Zweck des Abstract Factory Patterns besteht darin, eine Reihe von Produkten auszutauschen, die für die gemeinsame Verwendung hergestellt wurden. Das Builder-Muster dient dazu, den abstrakten Algorithmus zum Erstellen eines Produkts zu kapseln, um es für verschiedene Darstellungen des Produkts wiederzuverwenden.

Meiner Meinung nach kann man nicht sagen, dass das Abstract Factory Pattern der große Bruder des Builder Pattern ist. JA, beide sind Schöpfungsmuster, aber die Hauptabsicht der Muster ist völlig unterschiedlich.


nette Antwort, ausführlich erklären.
Towry


@ Rajdeep die Erklärung ist zu lang für einen Kommentar, deshalb habe ich eine andere Antwort geschrieben.
Janis

@ Janis Wo ist diese Antwort oder Quelle, von wo ich lesen kann?
Rajdeep

@ Rajdeep Ich empfehle Ihnen, das Buch „Design Patterns“ zu lesen - amazon.de/Patterns-Elements-Reusable-Object-Oriented-Software/…
Janis

7

Ein bemerkenswerter Unterschied zwischen Baumeister und Fabrik, den ich erkennen konnte, war der folgende

Angenommen, wir haben ein Auto

class Car
{
  bool HasGPS;
  bool IsCityCar;
  bool IsSportsCar;
  int   Cylenders;
  int Seats;

  public:
     void Car(bool hasGPs=false,bool IsCityCar=false,bool IsSportsCar=false, int Cylender=2, int Seats=4);
 };

In der obigen Oberfläche können wir Auto auf folgende Weise bekommen:

 int main()
 {
    BadCar = new Car(false,false,true,4,4);
  }

aber was ist, wenn beim Erstellen der Sitze eine Ausnahme auftritt? SIE ERHALTEN DAS OBJEKT NICHT // ABER

Angenommen, Sie haben eine Implementierung wie die folgende

class Car
 {
    bool mHasGPS;
    bool mIsCityCar;
    bool mIsSportsCar;
    int mCylenders;
    int mSeats;

 public:
    void Car() : mHasGPs(false), mIsCityCar(false), mIsSportsCar(false), mCylender(2), mSeats(4) {}
    void SetGPS(bool hasGPs=false)  {mHasGPs = hasGPs;}
    void SetCity(bool CityCar)  {mIsCityCar = CityCar;}
    void SetSports(bool SportsCar)  {mIsSportsCar = SportsCar;}
    void SetCylender(int Cylender)  {mCylenders = Cylender;}    
    void SetSeats(int seat) {mSeats = seat;}    
};

 class CarBuilder 
 {
    Car* mCar;
public:
        CarBuilder():mCar(NULL) {   mCar* = new Car();  }
        ~CarBuilder()   {   if(mCar)    {   delete mCar;    }
        Car* GetCar()   {   return mCar; mCar=new Car();    }
        CarBuilder* SetSeats(int n) {   mCar->SetSeats(n); return this; }
        CarBuilder* SetCylender(int n)  {   mCar->SetCylender(n); return this;  }
        CarBuilder* SetSports(bool val) {   mCar->SetSports(val); return this;  }
        CarBuilder* SetCity(bool val)   {   mCar->SetCity(val); return this;    }
        CarBuilder* SetGPS(bool val)    {   mCar->SetGPS(val); return this; }
}

Jetzt können Sie so erstellen

 int main()
 {
   CarBuilder* bp =new CarBuilder;
    Car* NewCar  = bp->SetSeats(4)->SetSports(4)->SetCity(ture)->SetGPS(false)->SetSports(true)->GetCar();

     bp->SetSeats(2);

     bp->SetSports(4);

     bp->SetCity(ture);

     bp->SetSports(true)

     Car* Car_II=  bp->GetCar();

  }

Hier im zweiten Fall würden Sie das Auto auch dann erhalten, wenn eine Operation fehlschlägt.

Vielleicht funktioniert das Auto später nicht mehr perfekt, aber Sie hätten das Objekt.

Weil die Factory-Methode Ihnen das Auto in einem einzigen Anruf gibt, während der Builder eins nach dem anderen baut.

Obwohl es von den Bedürfnissen des Deign abhängt, für wen man sich entscheidet.


2
Sicherlich ist es besser, überhaupt kein Auto als ein ungültiges Auto zu haben - was ist, wenn Sie das Problem nur finden, wenn Sie die Pausen nutzen?
Ken

@ Ken: Ich bestehe nicht darauf, dass es ein gutes Design aus der Perspektive eines kommerziellen Projekts usw. ist, sondern die Absicht, dieses Beispiel zu zitieren, um den Unterschied zwischen den Mustern zu veranschaulichen. Auf jeden Fall haben Sie Recht, dass dies aufgrund der Benutzererfahrung schlecht ist, wenn Sie ein schlechtes Auto bekommen, aber denken Sie daran, dass es ein Werk gibt, in dem Autos hergestellt werden und ein Teil fehlerhaft funktioniert, dann wird das Auto produziert, aber mit einer schlechten Pause, die bei herausgefunden werden würde Die Zeit des Testens und Versands dieses Autos an den Kunden wird gestoppt.
Fooo

2
Ich möchte klarstellen, dass ich tatsächlich ein großer Fan des Builder-Musters bin, jedoch nicht aus dem von Ihnen angegebenen Grund. Ein ungültiges Objekt sollte bei der Erstellung fehlschlagen. Je weiter unten im Prozess ein Fehler gefunden wird, desto teurer ist es. Mit dem Builder-Muster ist es normal, dass die Build-Methode (in Ihrem Beispiel getCar ()) eine Ausnahme auslöst, wenn erforderliche Daten fehlen.
Ken

7
+-------------------------------------------------------------------+---------------------------------------------------+
|                              Builder                              |                      Factory                      |
+-------------------------------------------------------------------+---------------------------------------------------+
| Return only single instance to handle complex object construction | Retrun various instances on multiple constructors |
| No interface required                                             | Interface driven                                  |
| Inner classes is involved (to avoid telescopic constructors)      | Subclasses are involved                           |
+-------------------------------------------------------------------+---------------------------------------------------+  

Teleskopkonstruktormuster

Analogie:

  • Fabrik: Betrachten Sie ein Restaurant. Die Erstellung des "heutigen Essens" ist ein Fabrikmuster, da Sie der Küche sagen, "Holen Sie mir das heutige Essen" und die Küche (Fabrik) anhand versteckter Kriterien entscheidet, welches Objekt generiert werden soll.
  • Builder: Der Builder wird angezeigt, wenn Sie eine benutzerdefinierte Pizza bestellen. In diesem Fall sagt der Kellner dem Koch (Baumeister): "Ich brauche eine Pizza; fügen Sie Käse, Zwiebeln und Speck hinzu!" Auf diese Weise macht der Builder die Attribute verfügbar, die das generierte Objekt haben sollte, verbirgt jedoch, wie sie festgelegt werden.

Höflichkeit


5

Builder und Abstract Factory haben für unterschiedliche Zwecke gedacht. Je nach richtigem Anwendungsfall müssen Sie ein geeignetes Entwurfsmuster auswählen.

Hauptmerkmale des Builders :

  1. Das Builder-Muster erstellt ein komplexes Objekt mit einfachen Objekten und einem schrittweisen Ansatz
  2. Eine Builder-Klasse erstellt das endgültige Objekt Schritt für Schritt. Dieser Builder ist unabhängig von anderen Objekten
  3. Ersetzen auf Factory-Methode / Abstract Factory in diesem Szenario: Zu viele Argumente, um vom Client-Programm an die Factory-Klasse übergeben zu werden, können fehleranfällig sein
  4. Einige der Parameter sind möglicherweise optional, anders als in Factory, wo alle Parameter gesendet werden müssen

Fabrik (einfache Fabrik) herausragende Merkmale:

  1. Schöpfungsmuster
  2. Basierend auf Vererbung
  3. Factory gibt eine Factory-Methode (Schnittstelle) zurück, die wiederum Concrete Object zurückgibt
  4. Sie können die Schnittstelle durch neue konkrete Objekte ersetzen, und der Client (Aufrufer) sollte nicht alle konkreten Implementierungen kennen
  5. Der Client greift immer nur auf die Benutzeroberfläche zu, und Sie können die Details zur Objekterstellung in der Factory-Methode ausblenden.

Entwürfe beginnen häufig mit der Factory-Methode (weniger kompliziert, anpassbarer, Unterklassen vermehren sich) und entwickeln sich zu Abstract Factory , Prototype oder Builder (flexibler, komplexer).

Schauen Sie sich verwandte Beiträge an:

Builder in einer separaten Klasse halten (fließende Schnittstelle)

Entwurfsmuster: Factory vs Factory-Methode vs Abstract Factory

Weitere Informationen finden Sie in den folgenden Artikeln:

Quellenherstellung

journaldev


5

Factory : Wird zum Erstellen einer Instanz eines Objekts verwendet, bei der die Abhängigkeiten des Objekts vollständig von der Factory gehalten werden. Für das abstrakte Fabrikmuster gibt es oft viele konkrete Implementierungen derselben abstrakten Fabrik. Die richtige Implementierung der Fabrik erfolgt über die Abhängigkeitsinjektion.

Builder : Wird zum Erstellen unveränderlicher Objekte verwendet, wenn die Abhängigkeiten des zu instanziierenden Objekts teilweise im Voraus bekannt sind und teilweise vom Client des Builders bereitgestellt werden.


4

Abstrakte Factory & Builder-Muster sind beide Schöpfungsmuster, jedoch mit unterschiedlicher Absicht.

Das abstrakte Fabrikmuster betont die Objekterstellung für Familien verwandter Objekte, wobei:

  • Jede Familie besteht aus einer Reihe von Klassen, die von einer gemeinsamen Basisklasse / Schnittstelle abgeleitet sind.
  • Jedes Objekt wird sofort als Ergebnis eines Aufrufs zurückgegeben.

Das Builder-Muster konzentriert sich darauf, Schritt für Schritt ein komplexes Objekt zu erstellen. Es entkoppelt die Darstellung vom Konstruktionsprozess des komplexen Objekts, sodass derselbe Konstruktionsprozess für verschiedene Repräsentationen verwendet werden kann.

  • Das Builder-Objekt kapselt die Konfiguration des komplexen Objekts.
  • Das Director-Objekt kennt das Protokoll zur Verwendung des Builders, wobei das Protokoll alle logischen Schritte definiert, die zum Erstellen des komplexen Objekts erforderlich sind.


3

Eine komplexe Konstruktion liegt vor, wenn das zu konstruierende Objekt aus verschiedenen anderen Objekten besteht, die durch Abstraktionen dargestellt werden.

Betrachten Sie ein Menü in McDonald's. Ein Menü enthält ein Getränk, ein Hauptgericht und eine Seite. Abhängig davon, welche Nachkommen der einzelnen Abstraktionen zusammengesetzt sind, hat das erstellte Menü eine andere Darstellung.

  1. Beispiel: Cola, Big Mac, Pommes Frites
  2. Beispiel: Sprite, Nuggets, Curly Fries

Dort haben wir zwei Instanzen des Menüs mit unterschiedlichen Darstellungen. Der Bauprozess bleibt wiederum der gleiche. Sie erstellen ein Menü mit einem Getränk, einem Hauptgericht und einer Beilage.

Mithilfe des Builder-Musters trennen Sie den Algorithmus zum Erstellen eines komplexen Objekts von den verschiedenen Komponenten, mit denen es erstellt wurde.

In Bezug auf das Builder-Muster ist der Algorithmus im Director gekapselt, während die Builder zum Erstellen der Integralteile verwendet werden. Das Variieren des verwendeten Builders im Algorithmus des Direktors führt zu einer anderen Darstellung, da andere Teile zu einem Menü zusammengesetzt sind. Die Art und Weise, wie ein Menü erstellt wird, bleibt gleich.


1
Dies erklärt die "Trennung der Konstruktion eines komplexen Objekts von seiner Darstellung"
Rajdeep

2

Der Hauptunterschied zwischen ihnen besteht darin, dass das Builder-Muster in erster Linie die schrittweise Erstellung komplexer Objekte beschreibt. Im Muster der abstrakten Fabrik liegt der Schwerpunkt auf Familien von Objektprodukten . Builder gibt das Produkt im letzten Schritt zurück . Im Abstract Factory-Muster ist das Produkt sofort verfügbar .

Beispiel: Nehmen wir an, wir erstellen Maze

1. Abstrakte Fabrik:

Maze* MazeGame::CreateMaze (MazeFactory& factory) {
Maze* maze = factory.MakeMaze(); /// product is available at start!!
 /* Call some methods on maze */
return maze;
}

2. Erbauer:

Maze* MazeGame::CreateMaze (MazeBuilder& builder) {
builder.buildMaze(); /// We don't have access to maze
 /* Call some methods on builder */
return builder.GetMaze();
}

2

Ich glaube, die Verwendung und der Unterschied zwischen Factory & Builder-Mustern können in einem bestimmten Zeitraum leichter verstanden / geklärt werden, da Sie an derselben Codebasis gearbeitet haben und sich die Anforderungen geändert haben.

Nach meiner Erfahrung beginnen Sie normalerweise mit einem Factory-Muster, das einige statische Erstellungsmethoden enthält, um in erster Linie eine relativ komplexe Initialisierungslogik zu verbergen. Wenn Ihre Objekthierarchie komplexer wird (oder wenn Sie mehr Typen und Parameter hinzufügen), werden Ihre Methoden wahrscheinlich mit mehr Parametern gefüllt, und ganz zu schweigen davon, dass Sie Ihr Factory-Modul neu kompilieren müssen. All diese Dinge erhöhen die Komplexität Ihrer Erstellungsmethoden, verringern die Lesbarkeit und machen das Erstellungsmodul anfälliger.

Dieser Punkt ist möglicherweise der Übergangs- / Erweiterungspunkt. Auf diese Weise erstellen Sie ein Wrapper-Modul um die Konstruktionsparameter und können dann neue (ähnliche) Objekte darstellen, indem Sie (möglicherweise) weitere Abstraktionen und Implementierungen hinzufügen, ohne die tatsächliche Erstellungslogik zu berühren. Sie hatten also "weniger" komplexe Logik.

Ehrlich gesagt ist es der Unterschied, sich auf etwas zu beziehen, bei dem "ein Objekt in einem oder mehreren Schritten erstellt wird", da der einzige Diversitätsfaktor für mich nicht ausreichte, um sie zu unterscheiden, da ich in fast allen Fällen, mit denen ich konfrontiert war, beide Methoden verwenden konnte jetzt ohne irgendeinen Nutzen zu erfahren. Das ist es also, worüber ich endlich nachgedacht habe.


2

Der Hauptvorteil des Builder-Musters gegenüber dem Factory-Muster besteht darin, dass Sie ein Standardobjekt mit vielen möglichen Anpassungen erstellen möchten, in der Regel jedoch nur wenige anpassen.

Wenn Sie beispielsweise einen HTTP-Client schreiben möchten, richten Sie einige Standardparameter wie Standard-Schreib- / Lesezeitlimit, Protokolle, Cache, DNS, Interceptors usw. ein.

Die meisten Benutzer Ihres Clients verwenden nur diese Standardparameter, während einige andere Benutzer möglicherweise einige der anderen Parameter anpassen möchten. In einigen Fällen möchten Sie nur die Zeitüberschreitungen ändern und den Rest unverändert verwenden. In anderen Fällen müssen Sie möglicherweise beispielsweise den Cache anpassen.

Es gibt folgende Möglichkeiten, Ihren Client zu instanziieren (aus OkHttpClient):

//just give me the default stuff
HttpClient.Builder().build()   

//I want to use custom cache
HttpClient.Builder().cache(MyCache()).build() 

//I want custom connection timeout
HttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).build() 

//I am more interested in read/write timeout
HttpClient.Builder()
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS).build()

Wenn Sie hierfür ein Factory-Muster verwenden, werden Sie am Ende viele Methoden mit allen möglichen Kombinationen von Erstellungsparametern schreiben. Mit dem Builder geben Sie einfach diejenigen an, die Sie interessieren, und lassen den Builder sie für Sie erstellen, wobei Sie sich um all diese anderen Parameter kümmern.


1

Das Erstellungsmuster betont die Komplexität des Erstellens eines Objekts (gelöst durch "Schritte").

Das abstrakte Muster betont "nur" die "Abstraktion" von (mehreren, aber verwandten) Objekten.


1

Der Unterschied ist klar. Im Builder-Muster erstellt der Builder einen bestimmten Objekttyp für Sie. Sie müssen sagen, was der Builder bauen muss. Im Factory-Muster erstellen Sie mit der abstrakten Klasse direkt das spezifische Objekt.

Hier fungiert die Builder-Klasse als Vermittler zwischen der Hauptklasse und bestimmten Typklassen. Mehr Abstraktion.


1

Beide sind sich sehr ähnlich. Wenn Sie jedoch eine große Anzahl von Parametern für die Objekterstellung haben, von denen einige optional sind und einige Standardwerte aufweisen, wählen Sie das Builder-Muster.


1

meiner bescheidenen Meinung nach

Builder ist eine Art komplexere Fabrik.

Aber in Builder können Sie Objekte instanziiert mit anderen Fabriken verwenden , die erforderlich sind , endgültig und gültiges Objekt zu bauen.

Wenn Sie also über die Entwicklung von "Schöpfungsmustern" nach Komplexität sprechen, können Sie folgendermaßen darüber nachdenken:

Dependency Injection Container -> Service Locator -> Builder -> Factory

1

Beide Muster haben die gleiche Notwendigkeit: Verstecken Sie die Konstruktionslogik eines komplexen Objekts vor einem Client-Code. Aber was macht "komplex" (oder manchmal kompliziert) ein Objekt? Hauptsächlich liegt es an Abhängigkeiten oder vielmehr am Zustand eines Objekts, das aus mehr Teilzuständen besteht. Sie können Abhängigkeiten nach Konstruktor einfügen, um den anfänglichen Objektstatus festzulegen. Für ein Objekt sind jedoch möglicherweise viele erforderlich. Einige befinden sich in einem anfänglichen Standardzustand (nur weil wir hätten lernen müssen, dass das Festlegen einer Standardabhängigkeit auf null nicht der sauberste Weg ist ) und eine andere Einstellung in einen Zustand, der von einer bestimmten Bedingung bestimmt wird. Darüber hinaus gibt es Objekteigenschaften, die eine Art "ahnungslose Abhängigkeiten" darstellen, aber auch optionale Zustände annehmen können.

Es gibt zwei bekannte Möglichkeiten, diese Komplexität zu beherrschen:

  • Zusammensetzung / Aggregation: Konstruieren Sie ein Objekt, konstruieren Sie seine abhängigen Objekte und verbinden Sie es dann. Hier kann ein Builder den Prozess, der die Regeln für die Konstruktion von Komponenten festlegt, transparent und flexibel gestalten.

  • Polymorphismus: Konstruktionsregeln werden direkt in der Subtypdefinition deklariert, sodass Sie für jeden Subtyp eine Reihe von Regeln haben und eine Bedingung entscheidet, welche dieser Regeln für die Konstruktion des Objekts gelten. Eine Fabrik passt perfekt in dieses Szenario.

Nichts hindert daran, diese beiden Ansätze zu vermischen. Eine Produktfamilie kann die mit einem Builder erstellte Objekterstellung abstrahieren. Ein Builder kann mithilfe von Fabriken bestimmen, welches Komponentenobjekt instanziiert wird.


0

Meiner Meinung nach wird das Builder-Muster verwendet, wenn Sie ein Objekt aus einer Reihe anderer Objekte erstellen möchten und die Erstellung eines Teils unabhängig von dem Objekt sein muss, das Sie erstellen möchten. Es ist hilfreich, die Erstellung von Teilen vor dem Client zu verbergen, um Builder und Client unabhängig zu machen. Es wird für die Erstellung komplexer Objekte verwendet (Objekte, die aus komplizierten Eigenschaften bestehen können).

Während das Factory-Muster angibt, dass Sie Objekte einer gemeinsamen Familie erstellen möchten und diese sofort bearbeitet werden sollen. Es wird für einfachere Objekte verwendet.


0

Baumeister und abstrakte Fabrik

Das Builder-Entwurfsmuster ist dem Abstract Factory-Muster in gewissem Maße sehr ähnlich. Deshalb ist es wichtig, in der Lage zu sein, den Unterschied zwischen den Situationen zu unterscheiden, in denen die eine oder andere verwendet wird. Im Fall der Abstract Factory verwendet der Client die Methoden der Factory, um eigene Objekte zu erstellen. Im Fall des Builders wird die Builder-Klasse angewiesen, wie das Objekt erstellt wird, und dann wird sie danach gefragt. Die Art und Weise, wie die Klasse zusammengesetzt wird, hängt jedoch von der Builder-Klasse ab. Dieses Detail macht den Unterschied zwischen den beiden Mustern aus.

Gemeinsame Schnittstelle für Produkte

In der Praxis haben die von den Betonbauern erstellten Produkte eine erheblich andere Struktur. Wenn es also keinen Grund gibt, unterschiedliche Produkte abzuleiten, wird eine gemeinsame Elternklasse verwendet. Dies unterscheidet auch das Builder-Muster vom Abstract Factory-Muster, mit dem Objekte erstellt werden, die von einem gemeinsamen Typ abgeleitet sind.

Von: http://www.oodesign.com/builder-pattern.html


-2

Das Factory-Muster erstellt zur Laufzeit eine konkrete Implementierung einer Klasse, dh die Hauptabsicht besteht darin, mithilfe des Polymorphismus zu entscheiden, welche Klasse instanziiert werden soll. Dies bedeutet, dass wir zur Kompilierungszeit nicht genau wissen, welche Klasse erstellt wird, während sich das Builder-Muster hauptsächlich mit der Lösung des Problems des Antipatterns von Teleskopkonstruktoren befasst, das aufgrund einer großen Anzahl optionaler Felder einer Klasse auftritt. Im Builder-Muster gibt es keine Vorstellung von Polymorphismus, da wir wissen, welches Objekt wir zur Kompilierungszeit konstruieren möchten.

Das einzige gemeinsame Thema dieser beiden Muster ist das Ausblenden von Konstruktoren und die Objekterstellung hinter Factory-Methoden sowie die Build-Methode für eine verbesserte Objektkonstruktion.


-2

Mit dem Factory-Muster können Sie ein Objekt sofort erstellen, während Sie mit dem Builder-Muster den Erstellungsprozess eines Objekts unterbrechen können. Auf diese Weise können Sie beim Erstellen eines Objekts verschiedene Funktionen hinzufügen.

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.