2013-03-09 16 views
6

ich die Builder PatternBuilder-Muster: Warum erstellt der Director das Objekt?

In dem obigen Link (Java-Beispiel) lerne, bemerkte ich, dass die Builder-Schnittstelle mehr Komponenten zu konstruieren bietet. Neben dem Aufruf rufen wir auch getProduct() auf.

Der Punkt, den ich nicht verstehe, ist, warum der Direktor all diese Komponenten-Konstrukt-Methoden eins nach dem anderen aufrufen und das Ergebnis am Ende bekommen muss.

 /** "Director" */ 
class Waiter { 
    private PizzaBuilder pizzaBuilder; 


public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; } 
public Pizza getPizza() { return pizzaBuilder.getPizza(); } 

public void constructPizza() { 
    pizzaBuilder.createNewPizzaProduct(); 
    pizzaBuilder.buildDough(); // construct component 1 
    pizzaBuilder.buildSauce(); // construct component 2 
    pizzaBuilder.buildTopping(); // construct component 3 
} 

}

Warum gehen wir nicht enthalten den Code für die Komponenten 1, 2, 3 in der ConcreteBuilder Klasse es sich von selbst, anstatt in dem Direktor, und in der Tat die Beseitigung der Direktor Schicht zu konstruieren.

Ich verstehe, dass der obige Ansatz das Builder-Muster in etwas anderes verwandeln könnte, aber ich verstehe nicht, warum der Director die Arbeit Schritt für Schritt erledigt. Was ist der Vorteil? Wenn es mehrere Directors gibt, wird es doppelten Code geben, richtig? Ich verstehe nicht das Motiv hinter der Ausführung des Builder-Musters ...

UPDATE: Konzentriert sich das Builder-Muster auf das Anbieten einer anpassbaren Komponentenauswahl beim Erstellen eines größeren komplexen Objekts? Ansonsten, ab sofort, sehe ich nicht den Punkt in der Einführung einer zusätzlichen Schicht, der Direktor.

Auch wenn das der Fall ist, könnte Dekorator-Muster eine bessere Idee sein, um dasselbe durch dynamisches Anpassen der Komponenten zu erreichen. Irgendwo fehlt mir der Punkt hinter dem Builder .. :(

+2

In der Tat eine gute Frage, auch nach dem Lesen der Antworten bekomme ich immer noch nicht, warum wir Regisseur Klasse brauchen. Es kann benutzerdefinierte Implementierung bieten, dann macht es Sinn. Sonst kein Punkt – Rohit

Antwort

5

Ich denke, Sie haben das Builder-Muster missverstanden. Sie sagen, dass der Prozess des Aufbaus der verschiedenen Komponenten in einer einzigen Methode zusammengeführt werden könnte, und das stimmt, aber ist nicht der Schlüssel dieses Objekterstellung Entwurfsmuster an diesem Code Schauen sie noch einmal.

class Waiter { 
    private PizzaBuilder pizzaBuilder; 

    public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; } 
    public Pizza getPizza() { return pizzaBuilder.getPizza(); } 

    public void constructPizza() { 
     pizzaBuilder.createNewPizzaProduct(); 
     pizzaBuilder.buildDough(); 
     pizzaBuilder.buildSauce(); 
     pizzaBuilder.buildTopping(); 
    } 
} 

Beachten sie, dass die Waiter funktioniert nur mit einer PizzaBuilder, weiß er nicht, ob es ein SpicyPizzaBuilder ist oder ein HawaiianPizzaBuilder und das ist die Ziel dieses Musters In diesem anderen Stück Code:

class BuilderExample { 
    public static void main(String[] args) { 
     Waiter waiter = new Waiter(); 
     PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder(); 
     PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder(); 

     waiter.setPizzaBuilder(hawaiianPizzaBuilder); 
     waiter.constructPizza(); 

     Pizza pizza = waiter.getPizza(); 

     waiter.setPizzaBuilder(spicyPizzaBuilder); 
     waiter.constructPizza(); 

     Pizza anotherPizza = waiter.getPizza(); 
    } 
} 

können Sie tatsächlich sehen, wie das funktioniert. Eine Waiter wird erstellt und zuerst eine HawaiianPizzaBuilder und dann eine SpicyPizzaBuilder übergeben, und mit der gleichen Instanz Waiter können Sie eine Pizza bauen und danach fragen, und er wird die richtige liefern. Hoffe, ich habe mich selbst erklärt und dieser Kommentar hilft dir;) Viel Glück !!!

+1

Hallo, vielen Dank für die Antwort. Die Sache, die ich immer noch nicht verstehe, ist, dass wir den Waiter nicht "nur" ConcretePizzaBuilder.createNewPizzaProduct() aufrufen lassen können und diese Methode die Schritt-für-Schritt-Erstellung von Komponenten und die Konstruktion von ganzen Objekten übernehmen lässt ?? – phani

+0

meine Frage aktualisiert, bitte überprüfen .. – phani

+0

@phani, ich sehe, was du meinst, und du hast recht, es ist nur ein anderer Weg, es zu tun. Du könntest mit einem einfachen Konstruktor wie 'public Pizza (Streichteig, Streichsoße, Streichgarnierung) {...}' gehen, aber das hat nichts mit dem Erbauermuster zu tun, mit anderen Worten: "Hey, Kellner macht mir eine hawaiianische Pizza und dann eine metropolitan Pizza, aber erzähl mir nicht wie, ich muss es nicht wissen. " Jajaja: D. Ich hoffe, dieser Kommentar hilft Ihnen, besser zu verstehen. – ecampver

4

Der Zweck der Klasse Director ist das Einkapseln des Algorithmus zum Erzeugen eines Objekts, d. H. Trennen des Codes für die Konstruktionslogik von dem Code für die Teile, aus denen das Objekt besteht. Ohne die Director-Klasse wäre Ihre Builder-Klasse sperriger und weniger modular, daher schwieriger zu warten und weniger wiederverwendbar.

Die Wikipedia example, auf die Sie sich beziehen, ist ziemlich einfach. Bei komplexen Objekten ist der Konstruktionsmechanismus normalerweise viel komplizierter, und der Direktor ruft die Builder-Methoden nicht notwendigerweise einzeln und in der Reihenfolge auf, in der sie definiert sind. Betrachten Sie zum Beispiel die Cake Klasse: Es kann Teile ChocolateLayer, CreamLayer und Strawberry haben.Der Builder würde die drei Methoden definieren für den Bau dieser drei Teile in dieser bestimmten Reihenfolge, aber die constructCake() Methode in der Director-Klasse wie folgt aussehen könnte:

public void constructCake() { 
    CakeBuilder.createNewCakeProduct(); 
    CakeBuilder.buildChocolateLayer(); 
    CakeBuilder.buildCreamLayer(); 
    CakeBuilder.buildChocolateLayer(); // 2nd call of the same Builder method 
    int totalStrawberries = 3 + new Random().nextInt(2); 
    for (int i = 1; i <= totalStrawberries; i++) 
     CakeBuilder.buildStrawberry(); // put some strawberries on top 
    // Please don't try this recipe at home! 
} 

Was die Unterschiede zwischen dem Generator und dem Ausstatter, Sie könnte die Builder Vs Decorator pattern Frage überprüfen.

+0

Das scheint mir eine richtige Antwort auf die erste Frage zu sein. Wir können zwei Directors haben, einer wäre HiltonCookDirector, der andere FourSeasonsCookDirector, beide wollen das gleiche Cake-Objekt erstellen (der spezifische CakeBuilder wird allgemeine Methoden haben, um seine Teile zu bauen), aber beide Directors haben unterschiedliche Schritte, wie sie es bauen wollen (man möchte doppelte Schokoladenschicht, die andere doppelte Cremeschicht usw. haben). –

+0

@TomasBilka Wenn Sie das gleiche Objekt mit anderen Mitteln herstellen, wäre eine abstrakte Fabrik eine bessere Wahl? – Jimbo

+0

@ Jimbo Ja und Nein. Der Builder soll sich mit komplizierten Objekten befassen, die mit einem gemeinsamen Build-Prozess "gebaut" werden. Factory kann alles aufbauen, wird aber nicht auf die Abstraktion von gemeinsamen Build-Phasen für ähnliche Objekte eingehen. –

1

Meine Erklärung des Builder-Musters: nehmen wir an, wir haben ein Objekt (Produkt) und diese Objektkonstruktion erfordert viele Parameter oder Komponenten (andere Objekte), um die Dinge noch schlimmer zu machen, werden nicht alle diese Parameter benötigt Das führt uns dazu, entweder viele Konstruktoren mit verschiedenen Parametern zu erstellen oder viele logische Anweisungen innerhalb des einzigen Konstruktors einzuführen, um dies zu wählen und dieses Objekt zurückzuweisen und um es noch schlimmer zu machen, dass diese Komponenten in einer Reihenfolge gebaut werden müssen (in einem (spezifische Sequenz) oder einige Business Rule-Checks auf sie, was alles darauf hinausläuft, ist ein komplexer Konstruktor, der eng an die Parameter (Komponenten) gekoppelt und schwer zu pflegen ist. Die Lösung besteht darin, diese Logik in einen konkreten Builder umzuwandeln, so dass wir unser Objekt erhalten, indem wir ConcreteBuilder.BuildComponent1(), ConcreteBuilder.BuildComponent2(), ..., ConcreteBuilder.GetMeMyObject() aufrufen, aber dies wird den Client-Code eng an den Konstruktionsprozess koppeln, jeder Client ist sich nun voll bewusst über alle Schritte, die erforderlich sind, um unser geliebtes Objekt zu konstruieren Jede Änderung im Konstruktionsprozess zwingt uns, den gesamten Client-Code hier und da zu modifizieren. Um das zu lösen, führt das Builder-Muster den Director ein, der diese Schritte einkapselt und nun alle Clients die Build() -Methode auf dem Director Director aufrufen um das Objekt zu bauen. Um das zusammenzufassen, ist der Director da, also Client-Code nicht wissen oder eng mit den Schritten verbunden sind, um unser geliebtes Objekt zu erstellen, warum sind diese BuildComponent1(), BuildComponent2() Methoden sind da, nun, sie sind da, um die Probleme der Erbauer zu lösen Muster gibt es für und was ich eingangs erwähnt habe: Wir können nun die Reihenfolge beim Komponentenaufbau durchsetzen, wir können auch Geschäftslogik erzwingen, die für jeden Betonbauer innerhalb dieser Methoden einzigartig ist, wir können sogar wählen, die Implementierung leer zu lassen bestimmte Betonbauer, weil einfach unser endgültiges Objekt (Produkt) diese Komponente nicht benötigt und wir diesen komplexen Konstruktionsprozess jetzt von unserem geliebten Objekt weg verkapselt haben, das seine Arbeit am besten erledigt, ohne sich Gedanken darüber zu machen, wie es sich selbst aufbauen soll.

+0

Danke für die Antwort. Könnten Sie bitte näher ausführen: "Weil wir jeden Teileerzeugungsprozess anpassen möchten." Meinten Sie, dass die Auswahl der Komponenten, aus denen das Endprodukt besteht, anpassbar ist? dh im Falle von Pizza können wir addSauce() nennen oder nicht, Builder stellt es zur Verfügung, aber es liegt an dem ConcreteDirector .. – phani

+0

@phani, Ihr stimmt teilweise, das Endprodukt ist anpassbar, aber nicht, weil wir eine Methode aufrufen und nicht einen anderen nennen, sondern weil jede Methode einen anderen Teil des Endprodukts ausmacht, so zwingen wir die Betonbauer tatsächlich dazu, ihre eigenen einzigartigen Teile des Endprodukts zu liefern, in Ihrem Beispiel verschiedene Arten von Pizzas mit verschiedenen Soßen und Toppings. –

+0

Danke für die Antwort. Aber was ich aus dem Sequenzdiagramm des Builder-Musters verstehe, ist, dass der Client einen Director erstellt und diesen mit "einem" ConcreteBuilder konfiguriert, so dass es aussieht, als würde man Teile von mehreren Buildern bekommen und es zu einem Objekt machen Erbauermuster. Ich entschuldige mich, wenn ich das Thema erweitern und Ihre Geduld testen werde. – phani

6

Der Director erstellt das Objekt nicht, der Builder, und es heißt das Produkt. Der Director ist aus einem einzigen Grund da: Die Benutzer der Klasse wissen nichts über die Schritte, die zum Erstellen des Objekts erforderlich sind. Das ganze Gerede darüber, alles in eine einzige Methode zu verfallen, ist wie die Frage, warum wir ein Auto nicht zu einem Einrad machen können. Wir könnten aber a. es wäre kein Auto mehr und b. es wäre nicht in der Lage, all die Dinge zu tun, die Autos tun, die Einräder nicht können.

Eine der besten Möglichkeiten, Builder zu betrachten, ist eine Verschmelzung von Template-Methode und Factory: Wir brauchen einen abstrakten Konstruktionsprozess, damit wir die Erstellung verschiedener Produkte unterstützen können, aber der Konstruktionsprozess beinhaltet viele Schritte. Sobald Sie die Director/Builder-Architektur implementiert haben, können Sie einfach neue Builder hinzufügen, indem Sie eine neue konkrete Implementierung bereitstellen. Es ist wie bei der Schablonenmethode, da der Builder die Details der Konstruktionssemantik ebenfalls ignorieren kann und nur Implementierungen für jeden erforderlichen Teil der Konstruktion liefern kann (beachten Sie auch, dass einige Logik in der abstrakten Basis der Builder-Hierarchie landen könnte) der automatischen Funktionalität, die die späteren Extender kostenlos bekommen).

+0

Danke für die Antwort. Soll das Builder-Muster mehrere Directors haben? oder ist es nur eine pro Anwendungsfall. – phani

+0

Eins. Der Direktor deckt den von Ihnen gesuchten Liner auf. Die Builder selbst stellen Implementierungen für die Teilelogik bereit. – Rob

+0

danke für die Antwort. Wenn es nur einen Director gibt, dh nur eine feste Schritt-für-Schritt-Prozedur, um Teile zu erstellen und das Objekt zu konstruieren, sehe ich keinen Unterschied zwischen dem Template-Muster und dem zusätzlichen Layer (Director), für den ich nicht weiß. Ich sehe den Nutzen. Ich habe versucht, nach Builder vs Template-Methode zu suchen, aber sie waren nicht zufriedenstellend. Ich hoffe, Sie verstehen meinen Punkt, und ich entschuldige mich für die erweiterte Konversation. – phani