Diskussion:Erbauer (Entwurfsmuster)
Füge neue Diskussionsthemen unten an:
Klicke auf , um ein neues Diskussionsthema zu beginnen.Zum Archiv |
Auf dieser Seite werden Abschnitte ab Überschriftenebene 2 automatisch archiviert, die seit 90 Tagen mit dem Baustein {{Erledigt|1=--~~~~}} versehen sind. |
UML Diagramm, besser Komposition
[Quelltext bearbeiten]Im UML Diagramm ist eine Aggregation zwischen Direktor und Erbauer dargestellt. Wenn aber, wie ich vermute, der Direktor das Erzeugen des Objektes an den Erbauer deligiert, muss eine Komposition verwendet werden.
- Es muss keine Komposition verwendet werden, es kann aber eine, oder auch einfach nur eine Assoziation. Ich glaube, der Aggregationspfeil ist ein Überbleibsel aus dem GoF-Buch, in dem an dieser Stelle auch ein Aggregationspfeil eingezeichnet sit. Sinnvoller ist aber in der Tat eine Assoziation. Um das Produkt zu bauen, muss der Direktor ja nur den Erbauer kennen, ihn nicht "im Bauch" habe, also selbst erzeugen. Wenn ich Zeit habe, werde ich das Bild entsprechend ändern. --Wikiplex 17:17, 25. Aug. 2009 (CEST)
Beispiel hinkt - bessere Beispiel Pizzeriabesitzer
[Quelltext bearbeiten]Hallo, m. E. hinkt das gegebene Beispiel und ist wenig intuitiv. Unter "Fahrzeug", "Geländewagen" und "Limousine" versteht man i. Allg. nichts, was selbst etwas baut, was also ein "Builder" ist. "Limousine erzeugt ein Auto" dürfte recht schwer zu verstehen sein für jemanden, der das Muster nicht kennt. ;-)
Ich würde das Beispiel gerne durch das in der engl. Wikipedia gegebene Beispiel des [Pizzabäckers] ersetzen, allerdings auch dies ein wenig angepasst und verbessert: Ein Pizzeriabesitzer (Director) stellt Pizzas (Product) her. Er kennt dazu die grobe Abfolge: legeTeig() -> legeSauce() -> legeBelag(). Er hat Pizzabäcker angestellt. Einen für Pizza Hawai (der den Teig dick, die Sauce süß und den Belag Ananas und Schinken legt) und einen für Pizza Picante (der den Teig dünn, die Sauce scharf und den Belag Peperoniwurst und Knoblauch legt). Diese leitet er durch Zuruf an (Methodenaufruf: "lege jetzt den Teig", ...) Ich finde, dieses Beispiel trifft das Muster exakt und ist für jeden sofort verständlich.
Hat jemand etwas dagegen? Ich kriege Hunger, während ich das schreibe... --Wikiplex 20:17, 25. Aug. 2009 (CEST)
- Die Builder-Beispiele haben alle so irgendwie den Nachteil, dass sie den eigentlichen Kernpunkt nicht treffen, weil sie *zu* einfach sind. Weder aus dem bisherigen, noch aus dem Pizza-Beispiel erkennt man den Sinn dahinter. "Warum der ganze Aufwand?" und "Für was braucht man den Direktor?" wird sich vielleicht der ein oder andere fragen. Der Punkt ist hier ja, dass der Direktor die Reihenfolge kennt, diese aber nicht statisch sein muss. Die ganzen Beispiele sind aber statisch und so merkt man nix von der Entkopplung von Struktur und konkreter Realisierung. Das Beispiel im GoF-Book ist da passender. --Der Hâkawâti ✉ 22:10, 27. Aug. 2009 (CEST)
- Hallo! Welches Beispiel aus dem GoF-Buch meinst du? Das mit dem RTFReader (=Direktor), der RTF liest und daraus je nach Builder ASCII, TeX oder TextWidget macht? Du meinst mit "nicht statisch", so nehme ich an, dass dort die Reihenfolge nicht a priori feststeht, weil da eine Schleife mit einem Switch drin ist. Ich sehe die "Nicht-Statizität" nicht als Kernpunkt an, und sie ist im GoF-Buch auch nicht als Kriterium für die Anwendbarkeit gedacht ("Applicability"). Es ist ja auch im dortigen Beispiel immer derselbe Builder, der innerhalb der Schleife benutzt wird. Außerdem kann man argumentieren, dass dort die Reihenfolge nur aus einer Schleife mit einem Switch drin besteht, was wiederum statisch ist. (Oder ich habe nicht richtig verstanden, was du mit "statisch" meinst.) Grüße! --Wikiplex 22:30, 27. Aug. 2009 (CEST)
- Ja das Beispiel mein ich. Und ja die Schleife mit dem Switch halte ich für wichtig. Das heißt natürlich nicht, dass immer genau so eine Konstruktion auftauchen muss. Deshalb ist das ja auch nur Teil des Beispiels und nicht Teil des Patterns. Mit „statisch“ meine ich aber nicht, dass der Builder nicht wechselt, sondern die Reihenfolge der Teile, die der Builder baut. In einem Dokument können 5 Absätze sein und dann kommt n FontChange und in nem anderen Dokument kommen zwei Absätze und gar keine FontChanges. Es sind also nicht nur die Teile, die Komplexität besitzen (darum kümmern sich die Builder), sondern auch das Ganze, das "complex object", besitzt Komplexität (darum kümmert sich der Diektor). Und genau das steht auch unter Applicability: "Use this pattern when the algorithm for creating a complex object should be independent of the parts [...] and how they're assembled." Wichtig ist also, dass es sich um ein komplexes Objekt handelt (wobei hier „Objekt“ nicht im OOP-Sinne zu verstehen ist). Und das ist bei den Beispielen nicht der Fall. Es wird dadurch nicht klar, was der Direktor macht. Zumindest ist es mir nicht klar geworden, bevor ich das Beispiel im GoF-Book gelesen hab. --Der Hâkawâti ✉ 23:03, 27. Aug. 2009 (CEST)
- Ich gebe dir in allen Punkten recht. Die Diskussion ist gut und fruchtbar; wir sollten sie in den Artikel einfließen lassen! Wir brauchen aber noch ein gutes Beispiel, ohne GoF abzukupfern. Aus deiner Argumentation folgt, dass die Methode Director.Construct() parametrisiert werden muss mit einer komplexen (d.h. nicht-trivialen) Bauanleitung. Das läuft daraus hinaus, dass irgendetwas zerlegt (geparst) werden muss, um das Produkt zu bauen. Vielleicht sollten wir in Richtung Parsen denken. (So ist ja auch das GoF-Beispiel.) Grüße! --Wikiplex 23:59, 27. Aug. 2009 (CEST)
- Ja ein eigenes Beispiel kann nicht schaden. Etwas anderes als Parser/Konverter fällt mir aber momentan auch nicht ein... --Der Hâkawâti ✉ 21:16, 28. Aug. 2009 (CEST)
- Ich glaube, ich hab jetzt ein passendes Beispiel gefunden: Ein Kaffee-Automat. Und zwar einer von der Sorte, die unterschiedliche Sorten Kaffee zubereiten können: Cappuccino, Latte Macchiato, etc. Dazu nimmt der Direktor ein Rezept, das er beispielsweise aus ner Konfigurationsdatei liest(das Ganze soll sich leicht erweitern lassen ohne den Code anfassen zu müssen). Unsere Software soll jetzt aber auch auf unterschiedlichen Kaffeemaschinen funktionieren, weil wir beispielsweise für unterschiedliche Hersteller die Firmware schreiben und nicht immer alles neu schreiben wollen. Dem tragen die Builder Rechnung. So ist der abstrakte Builder quasi eine Hardwareabstraktion und die konkreten Builder spezifisch für einen bestimmten Typ Kaffeemaschine. --Der Hâkawâti ✉ 12:05, 29. Aug. 2009 (CEST)
- Ich sehe zwei Probleme mit deinem Beispiel: (1) Es ist ziemlich viel Code, wenn du ein komplettes, kompilierfähiges Beispiel abliefern willst. (Allein das Parsen des Rezeptes ist ja schon aufwändig; und wie ist ein Rezept überhaupt aufgebaut?) (2) Dein Beispiel suggeriert, dass das Builder-Pattern hauptsächlich dazu da ist, um plattformunabhängige Software zu schreiben. Dazu kann es auch verwendet werden, es ist aber m. E. nicht der Hauptzweck. Aber vielleicht wilst du dein Beispiel mal programmieren? Schadet ja nichts, mehrere zu haben, evtl. in mehreren Sprachen.
- Ich habe eher an so etwas gedacht wie irgendwelche Datensätze einmal nach CSV und einmal nach XML umzuwandeln. Beispielsweise als Ausgangsformat Aktienkurswerte, je einer pro Zeile: "Zeit WKN Kurs Gehandelte_Stücke". Das ist leicht zu parsen (zeilenweises Einlesen/Split an Leerzeichen) und dann Umwandeln nach CSV oder XML. Es könnte sich dabei um ein Altlast-Format (legacy format) oder um das interne Format einer Börsensoftware handeln. (Die Werte könnten ja auch in Structs stehen.) Nur der Director weiß, wie die Werte zu interpretieren sind. --Wikiplex 09:38, 1. Sep. 2009 (CEST)
- (1) Vermutlich kompilieren die wenigsten meiner Code-Beispiele. Ich bin Fan von Pseudocode. Beispiele müssen vor allen Dingen verständlich sein und das Notwendige zeigen. Ob sie kompilieren ist mir dabei nicht so wichtig.
- (2) Da hast du natürlich Recht.
- zu deinem Vorschlag: Ich find den gut. Der ist noch verständlicher als meiner und wie erwähnt, halte ich Verständlichkeit hier für am wichtigsten...
- --Der Hâkawâti ✉ 12:22, 1. Sep. 2009 (CEST)
So, habe vorgelegt und das Aktienkurs-Beispiel implementiert und in den Artikel eingebaut und warte auf Kommentare. Außerdem habe ich die Diskussion wieder nach links gezogen, weil uns allmählich die Einrücktiefe in den Abgrund führt. Zu (1): Ich bin Fan von vollständigen, ausführbaren Programmen. Wenn sie als Beispiel machbar sind (d.h., wenn sich die Länger überschaubar hält), dann ist die Ausführbarkeit für mich das Sahnehäubchen auf dem gelungenen Beispiel: Man kann einfach direkt damit rumexperimentieren. Aus vielen Programmierkursen, die ich gehalten habe, weiß ich, dass es für sehr viele Lernende wichtig ist, dass auf dem Bildschirm etwas flackert und blubbbert und dass man direkt etwas ausprobieren kann. Grüße! --Wikiplex 16:22, 1. Sep. 2009 (CEST)
- Zu Pseudocode oder nicht: Ich denke es ist ein Unterschied, ob das Thema Programmierung oder Design ist. Bei nem Programmierkurs ist Kompilierbarkeit natürlich sehr wichtig. Wenn ich mich aber mit Patterns beschäftige... kann zugegebenermaßen Kompilierbarkeit auch nicht schaden, ist IMHO aber eher zweitrangig. Egal. Zum Beispiel: Ich finde es gut gelungen. Praxisnah und anschaulich. Ein paar kleine Anmerkungen hab ich aber doch:
- >>> Die Werte könnten auch innerhalb der Anwendung in einer Liste von Verbünden gespeichert sein. <<< Das ist zwar richtig, passt aber nicht zum Code. Idee ist wohl zu sagen "Das hier is nur n Beispiel, man kanns auch anders machen". Das aber signalisiert ja schon die Überschrift. Das allein wär ja noch nicht tragisch, aber denk dir mal, du würdest weder das Builder-Pattern richtig kennen, noch das Beispiel. Und jetzt lies bis zu dieser Stelle. Ist das verständlich? Ich könnte mir vorstellen, dass das den Leser eher verwirrt. Das mit dem legacy format geht noch (würd ich aber auch rauslassen). Aber spätestens bei diesem Satz werden sich viele erstmal fragen, was gemeint ist. Lieber erstmal nur das Wichtige sagen; nicht zu sehr ins Detail gehen. Infos kann man, wenns wirklich wichtig ist, später immer noch nachschieben. Das ist auch der Grund, warum ich Pseudocode so toll finde. Man kann den Detailgrad beliebig wählen und nur das zeigen, was zum Verständnis notwendig ist. Das macht die Beispiele übersichtlicher. So würde ich hier also erstmal die "Zusatzinfos" weglassen.
- Beim XML-Beispiel fehlt das
<?xml version="1.0" encoding='UTF-8'?>
- >>> Einsatz des Erbauer-Musters zur flexiblen Architektur <<< Da passt was nicht. Es geht hier um ein Entwurfsmuster und nicht um Architektur. Da liegt ne Abstraktionsebene dazwischen...
- >>> Kursumwandlung <<< Nicht die Kurse werden umgewandelt, sondern das Datenformat. Die Kurse sollten dabei nach Möglichkeit ja gleich bleiben.
- >>> LatexKursdatenBauer <<< LaTeXKursdatenBauer. Es geht hier ja nicht um Gummi... ;-)
- >>> friend class KursdatenLeser; <<< Huch, was machst du denn da? Die Methoden protected nur um künstlich die Notwendigkeit für friend zu schaffen? Oder ist das ein C++-Ideom, das ich nicht kenne?
- >>> (das auch als Objekt vom Typ CSVDatei zurückgegeben werden könnte) <<< Wieder so eine Stelle über die ich gestolpert bin. Ich wusste zuerst nicht, was du meinst. Gedanke ist hier wohl, dass es nicht unbedingt schön ist, in ner verarbeitenden Klasse direkt auf die Standardausgabe zu schreiben. Das sehe ich auch so. Zumal in meinen Augen Musterbeispiele auch mustergültig sein sollten. Warum also nicht einfach im Konstruktor einen Stream übergeben? Dann hat man den Kommentar gespart und der Code ist sauberer.
- So, jetzt fällt mir nix mehr ein, was ich noch meckern könnte. Ansonsten wirklich ein gutes Beispiel! --Der Hâkawâti ✉ 21:35, 1. Sep. 2009 (CEST)
- Ich habe alles gem. deinen Kommentaren geändert bis auf:
- Bei einem XML-Dolument darf der sogenannte Prolog (das
<?xml version="1.0" ?>
) leer sein, also nicht vorhanden. - Die friend-Konstruktion ist hier doch ein typisches Beispiel für eine Aggregation: Die Erbauer sollen ausschließlich vom Direktor und von ihren Unterklassen angestossen werden. (Daher sind die Methoden protected und durch friend kann der Direktor sie anstossen). Der (implizite) Konstruktor dagegen ist public, damit der Klient ihn anlegen und dem Direktor übergeben kann.
- Die Idee mit dem Stream im Konstruktor ist ganz richtig. Ich habe angefangen, das einzuprogrammieren, habe dann aber aufgehört, weil der Code zu groß wird: Man braucht ja 3 Konstruktoren mehr, muss da explizit "public" hinschrieben usw. Stattdessen habe ich den Kommentar geändert. --Wikiplex 14:31, 2. Sep. 2009 (CEST)
- Bei einem XML-Dolument darf der sogenannte Prolog (das
- Ich habe alles gem. deinen Kommentaren geändert bis auf:
- OK, wenn man das weglassen kann, ist es gut. Ich dachte das wäre nötig. Ich merke mal wieder, dass XML auf meiner ToDo-Liste steht...
- Das ist also ein C++-Idiom? Interessant. Trotzdem halte ich es - zumindest beim Builder-Pattern - nicht für so gut. Erbauer und Direktor sollen ja gerade entkoppelt werden, so werden sie aber wieder stärker gekoppelt. Das hat zur Folge, dass der Direktor nicht mehr ausgetauscht werden kann ohne den Builder anzufassen. Sehr unschön.
- Mit dem Kommentar ist das jetzt verständlich so, denke ich.
Mal rein aus Interesse: Warum drei zusätzliche Konstruktoren?*denkt* Ach ja, in C++ werden Konstruktoren ja gar nicht vererbt. Da muss ich irgendwann auch mal rausfinden, warum das so ist...
- --Der Hâkawâti ✉ 20:34, 2. Sep. 2009 (CEST)
- S. Regel [22] auf http://www.w3.org/TR/REC-xml/#sec-prolog-dtd
- Ja, ein C++-Idiom. Klar sollen Erbauer und Direktor entkoppelt werden, aber der Direktor soll doch nicht austauschbar sein: Du hast mich doch selbst darauf aufmerksam gemacht, dass ein wesentlicher Punkt des Musters darin besteht, dass der Direktor - und nur Direktor - den Algorithmus zum Parsen und Zusammenbauen kennt! Der Klient soll also nur den (festen) Direktor benutzen. Der Klient weiß doch gar nicht, wie das umzuwandelnde Format aufgebaut ist, also kann er sich auch keine verschiedenen Direktoren aussuchen. (OK, man könnte sich für maximale Flexibilität noch eine Hierarchie von Direktoren vorstellen, die sich beim Parsen z.B. in ihrem Speicherplatz-vs.-Laufzeit-Verhalten unterscheiden. Jedenfalls liegt es dann immer noch in der Verantwortung des Framework-Erschaffers, die Erbauer-Klassen dann zu Freunden zu machen. Der Klient sieht nichts davon.) Die Alternative ist, die Methoden schreibeKursdaten() usw. öffentlich zu machen. Dann kann der Klient aber so was sagen wie
XMLKursdatenBauer xmlKursdatenBauer; xmlKursdatenBauer.schreibeKursdaten(...);
- was eine unsinnige Ausgabe erzeugt. Er soll den Umweg über den Direktor gehen. Ich lasse mir aber gerne ein anderes Design zeigen, das diesen Weg verbietet, ohne den Direktor zu einem Freund zu machen. (Muss ja in Java irgendwie gehen. Du wirst mir wahrscheinlich antworten, dass der Direktor eine zusätzliche Methode haben soll: wähleKursdatenBauerAus(...), die dann je nach Argument einen bestimmten Erbauer erzeugt und assoziiert. Das macht das Muster aber komplexer.) --Wikiplex 14:37, 6. Sep. 2009 (CEST)
- Danke für den Link! :-)
- Warum soll der Direktor nicht austauschbar sein? Beschränkungen baut man nur ein, wenn man einen Grund dazu hat. >>> Du hast mich doch selbst darauf aufmerksam gemacht, dass ein wesentlicher Punkt des Musters darin besteht, dass der Direktor - und nur Direktor - den Algorithmus zum Parsen und Zusammenbauen kennt! <<< Genau. Das heißt, dass die Erbauer davon keine Ahnung haben dürfen. Im konkreten Fall: In dem Erbauer-Klassen steckt kein Code, der das Design darauf festnagelt, wie die Struktur zustande kommt. Der Direktor könnte das auch aus Binärdateien auslesen, vom Benutzer erfragen oder per Post zugeschickt kriegen. Man soll den Direktor aber genau deshalb auch austauschen können. Vielleicht willst du dein Programm erweitern, dass nicht nur das Legacy-Format gelesen wird, sondern wirklich der Benutzer danach gefragt wird. Das wäre dann ein weiterer Direktor. Ansonsten müsstest du für dieses Szenario das Schreiben der xml-Files nochmals implementieren! Und genau das bedeutet es auch, dass zwei Klassen entkoppelt sind. Beide können mehr oder weniger beliebig ausgetauscht werden. Durch den friend-Trick verhinderst du die Hälfte der Freiheiten, die dir das Muster bietet. Entkopplung bedeutet also nicht, dass es keine anderen Klassen geben darf, die den Erbauer benutzen. >>> Dann kann der Klient aber so was sagen wie <<< Du kannst jede Klasse falsch benutzen. Das Builder-Pattern entkoppelt ja nicht die Erbauer, von der Bedienung derselben, sondern die Konstruktion (mit anderen Worten die Struktur, den Input), gegeben durch den Direktor, von der Repräsentation (dem Output), gegeben durch die Erbauer. --Der Hâkawâti ✉ 16:54, 6. Sep. 2009 (CEST)
- Ich wollte zuerst schreiben "Meiner Meinung nach passen die Erbauer zu genau dem einen Direktor. Wenn ich ein anderes Format parsen und umwandeln will, brauche ich einen ganz anderen Direktor und ganz andere Erbauer. Das sieht man doch auch an der problemspezifischen Signatur
schreibeKursdaten(const string& wkn, const string& name, const string& kurs, const string& stueckzahl)
." Beim Schreiben ist mir aufgefallen, dass das Quatsch ist. Hast recht. Der XML-Erbauer kann auch für einen MSExcel->XML-Wandler benutzt werden. Trotzdem: >>> Du kannst jede Klasse falsch benutzen. <<< Ein gutes Framework minimiert diese Gefahr. Ich will die Methoden des Erbauers nicht public machen. Der Klient soll diese Methoden überhaupt nicht sehen. Die einzige Lösung, die mir einfällt, ist, dass der Direktor pro Ausgabeformat eine Konstante definiert (alsoKursdatenBauer::XMLAusgabe
usw.), die der Klient dann insetzeAusgabeFormat(...)
übergeben kann; der Direktor legt sich dann demgemäß seinen Erbauer an (und hat ein Default-Ausgabeformat). Aber das macht das Beispiel komplizierter und lenkt den Erstleser wieder vom Wesentlichen ab. Vielleicht sollten wir die Methoden dann halt doch public machen und in einem eigenen Unterpunkt "Implementierung" eine sicherere Implementierung beschreiben. --Wikiplex 19:35, 6. Sep. 2009 (CEST)
- Ich wollte zuerst schreiben "Meiner Meinung nach passen die Erbauer zu genau dem einen Direktor. Wenn ich ein anderes Format parsen und umwandeln will, brauche ich einen ganz anderen Direktor und ganz andere Erbauer. Das sieht man doch auch an der problemspezifischen Signatur
- >>> Ein gutes Framework minimiert diese Gefahr. <<< Richtig. Die Frage ist nur hier, ob das Verhindern des Zugriffs auf die Builder hier sinnvoll ist. BTW: Builder sind nicht nur etwas für Frameworks. Im Gegenteil: Ich bin momentan eher der Meinung, dass das häufiger in normalen Anwendungen auftaucht...
- >>> Ich will die Methoden des Erbauers nicht public machen. <<< Will es das Muster auch nicht? Ich denke, dass es sie public haben wollen würde.
- >>> Der Klient soll diese Methoden überhaupt nicht sehen. <<< Das Blöde ist: Wenn du dem Client verbietest die Methoden überhaupt zu sehen, verhinderst du auch Erweiterungen. Konkret: Neue Direktoren. Manches lässt sich leider nicht sinnvoll verhindern. Zumindest finde ich für diesen Fall keine sinnvolle Möglichkeit. (Ich lass mir aber gern eine zeigen.) Wobei sich auch die Frage stellt, ob es wirklich sinnvoll ist, den Zugriff zu verbieten. Was spricht dagegen, dass der Client eine Builder-Klasse losgelöst von seiner Funktion als Builder benutzt? Die Klassen in den Mustern sind ja "nur" Rollen und werden im Idealfall auf bestehende Klassen gemappt. Eine Klasse kann also auch andere Rollen (ggf. in anderen Mustern) übernehmen. So könnte der Client im Beispiel benutzen um ein leeres XML-Dokuemnt zu erzeugen. Dazu ruft er
initialisiereSchreiben(); beendeSchreiben();
auf. Das ist zu trivial für eine separate Direktor-Klasse, kann also direkt der Client machen (man kanns auch anders sehen: Die Direktor-Rolle wird auf die Client-Klasse gemappt). Wenn du hier irgendwelche Beschränkungen einführst, verbaust du dir sinnvolle Wege. - >>> dass der Direktor pro Ausgabeformat eine Konstante definiert <<< Sry, aber IMHO ganz schlecht. So koppelst du ja wieder den Direktor an die Builder, d.h., wenn du einen neuen Builder schreibst, müsstest du alle Direktoren anpassen.
- >>> der Direktor legt sich dann demgemäß seinen Erbauer an <<< Ist das Aufgabe des Direktors? IMHO ist es Aufgabe des Clients auszusuchen, welchen Direktor und welchen Erbauer er haben will. Hier böte sich DependencyInjection an.
- >>> in einem eigenen Unterpunkt "Implementierung" eine sicherere Implementierung beschreiben. <<< Wie schon gesagt bin ich nicht so überzeugt davon, dass eine "sicherere" Implementierung sinnvoll ist. Ich sehe da mehr Nach- als Vorteile. --Der Hâkawâti ✉ 22:50, 6. Sep. 2009 (CEST)
- Ich glaube, die Schlüsselfrage ist wirklich, ob hier ein Framework geschaffen werden soll oder nicht.
- In einem guten Framework (z.B. Java AWT) findest du keine Klasse, die du instanziieren kannst und bei der du dann in der Doku eine Methode wie
schreibeKursdaten()
findest, von der du nicht verstehst, wozu du sie (jemals) benutzen sollst. Im Framework sollst du nurkursdatenLeser.parseUndSchreibeKursdaten()
sagen können. (Würdest du dich nicht, wenn ich dir die Klassen des Beispiels [mit public-Methoden] als Framework verkaufen würde, damit du eine Umwandlung Altformat->Neuformat vornehmen kannst, fragen, was diese „komischen“ Methoden in den KursdatenBauern sollen?) Hierfür finde ich meinen Vorschlag mit den Konstanten (KursdatenLeser::XMLAusgabe
usw.) akzeptabel, auch wenn dadurch der Direktor an den Builder gekoppelt wird. Dem Klienten wird ja nur ein fixes API und Framework ausgeliefert. Der Erschaffer des Frameworks dagegen kennt seine Kopplungen, und sooo viel Aufwand ist es ja für ihn auch nicht, beim Hinzukommen eines neuen Builders neue Konstanten und den Selektionscode dafür zu schreiben. - Da wir aber nicht wissen oder davon ausgehen können, ob der Builder nur für ein Framework da ist (wohl eher nicht), sind deine Argumente stichhaltig, und ich mache daher die entsprechenden Methoden public und nehme das friend raus. --Wikiplex 10:33, 7. Sep. 2009 (CEST)
- In einem guten Framework (z.B. Java AWT) findest du keine Klasse, die du instanziieren kannst und bei der du dann in der Doku eine Methode wie
- Ich glaube, die Schlüsselfrage ist wirklich, ob hier ein Framework geschaffen werden soll oder nicht.
Alternativvorschlag
[Quelltext bearbeiten]Ich finde das momentane C++ Beispiel trifft nicht so richtig den Gedanken hinter dem Muster. Ich habe meinen Vorschlag eingereicht: https://de.wikipedia.org/w/index.php?title=Erbauer_(Entwurfsmuster)&oldid=126871205 --Sebmes (Diskussion) 10:02, 26. Jan. 2014 (CET)
- Ich denke auch, dass dein Beispiel besser sein könnte als das C++ Beispiel (hab es aber gelöscht, da sonst 2 Beispiele). Möchte zu deinem Beispiel aber noch folgende Überlegungen anbringen: 1) der konkrete Builder sollte nicht nur die Attribute sammeln, sondern das Ding als gesamtes zurückgeben können (wenn es fertig gebaut ist) - siehe "getResult" Methode in der Grafik. d.h. dein Interface sollte keine getter haben, dein ConcreteSmartphoneBuilder eine getConcreteSmartphone() die das (spezifische) Endprodukt (ConcreteSmartphone) zurückgibt. 2) vielleicht verwendest einen spezielleren Namen als "ConcreteSmartphone" - z.B. mach einen AndroidPhoneBuilder, der sicherstellt, dass z.B. alle Android-Smartphones einen Touchscreen haben 3) vielleicht zeigst bei den vielen Konstruktoren auch das Problem, dass Konstruktoren keinen Namen haben, also public Smartphone(double displaySize, String osName, int cpuSpeed) sich nicht von public Smartphone(double displaySize, String osName, int batteryCapacity) unterscheiden lässt. Das könnte man natürlich auch mit Factory Methoden lösen aber ein Builder löst dieses Problem auch. --Sebastian.Dietrich ✉ 10:27, 26. Jan. 2014 (CET)
- P.S. Du könntest bei dem Beispiel auch auf Fluent Interface eingehen - d.h. die setter geben den konkreten Builder wieder zurück und in der Main Methode kannst sagen SmartphoneBuilder b2 = new ConcreteSmartphoneBuilder(4).setOperationsystem("iOS").setCpuSpeed(1200).setBatteryCapacity(1440);
--Sebastian.Dietrich ✉ 10:33, 26. Jan. 2014 (CET)
Zu Kompliziert
[Quelltext bearbeiten]Hey *,
schaut man sich den Artikel in der Englischen Wikipedia an findet verständliche Beispiele in diversen Programmiersprachen in einer vernünftigen Länge. Insbesondere C++ ist in meinen Augen bei weitem nicht so gut lesbar wie eine Java, C#, JavaScript Implementierung.
Nachdem ja auch einige sehr große Libs (StringBuilder in Java) mit dem Builder Pattern ohne Director daherkommen sollte man diese Option nicht außer acht lassen.
Ich würde folgendes Beispiel heranziehen (nachdem das auch in der deutschen Wikipedia gut dokumentiert ist):
Der Chef de Cuisine ist unser Director (der analog zum Pattern eigentlich auch weiß wie man alles Kocht aber in der Realität eher mit dem zusammensetzen der einzelnen Teile eines Gerichts beschäftigt ist). Dann gibts die Chef de Partie (Saucier, Rôtisseur, usw.) die Kochen Implementationen von Essen die wiederum vom Director zu einem Gericht zusammengesetzt werden. Das sollte das Pattern relativ gut abdecken. Ich würde vorschlagen es in Java zu entwickeln und ganz bewusst auf einige Funktionen verzichten, so dass es dann auch nicht kompilierfähig ist.