Welche Design Patterns sollte man kennen?
-
hustbaer schrieb:
Argh. Sorry, vergiss es, ich hätte genauer lesen sollen.
Ja, ein Design-Pattern ist bleibt ein Design-Pattern, unabhängig davon ob es in einer Sprache einfach oder schwer zu implementieren ist.
Was Pimpl angeht... von miraus soll es kein "Design Pattern" sein, mir im Prinzip egal. Ein Pattern ist es für mich auf jeden Fall.
Es ist viel mehr mehr. Es ist ein Prinzip. Nennt sich Dependency Inversion.
-
Apollon schrieb:
antwort schrieb:
hustbaer schrieb:
@dumme antwort: viele der sog. Design Patterns sind aber Implementierungs-Details.
Also irgendwann muss man das ganze implementieren. Ob ich z.B. ein Observerpattern mit Interface/Klassen und virtuellen Methoden, Strukturen und Funktionpointern oder einfach mit ein Sprachfeature umsetze ist ein Detail. Deswegen ändert sich nicht das Design.
Wenn du jetzt von sogenannten Design Pattern redest, weiß ich nicht was du meinst, aber es sind wohl dann keine richtigen.Demnach ist Design die reinste formale Modellierung. Alles andere ist Implementierungsdetail.
Ich fuer meinen Teil sehe es genauso wie Helium. Sprachunzulaenglichkeiten werden durch Design-Pattern kompensiert. Bei Entwicklung neuer Sprachen werden Design-Pattern beruecksichtigt und soweit moeglich als Sprachfeature integriert. Das Ganze ist ein iterativer Prozess, da es mehr Probleme gibt als Loesungen und fuer jedes Problem mehrere Loesungen existieren.
BTW: http://l04.iue.tuwien.ac.at/VO/VO_cpp/teil1/foil04.html entspricht exakt Heliums Aussage.
Der Unterschied ist, dass Design Patters nicht sagen wie man etwas in einer bestimmten Sprache umsetzt (was Idioms machen), sondern allgemeine Lösungen für immer wieder auftretende Probleme beim Software Design sind. Darum sind sie auch nicht dazu da Sprachunzulänglichkeiten zu kompensieren, was Idioms machen.
-
Erklär mir doch einfach mal das Strategy Pattern mit kleinen konkreten Minimalbeispielen in einer Sprache in der Funktionen first class sind und die ordentliche Closures hat (Lisp, Dylan, O'Caml, ... mir ist alles recht). Anschließend könntest du mir dann noch Anwendungen des Command Pattern in der selben Sprache zeigen.
(Info am Rande: Closures sind schon lange bekannt bevor überaupt die erste objekorientierte Sprache erdacht wurde.)
-
Ich kenn keine dieser Sprachen. Sag mir doch einfach was das Problem sein soll.
-
Du behauptest, dass Design Pattern "Lösungen für immer wieder auftretende Probleme beim Software Design sind". Was aber, wenn das, was von dem Design Pattern versucht wird zu Lösen, gar kein Problem ist, sondern eine Trivialität, für die ich nichts konstruieren muss. Mit Closures ist das Strategy Pattern in etwa so aufwendig, wie eine belibige Variable anzulegen. Mit Closures ist das Command Pattern ebenso aufwendig. Beides wird plötzlich durch ein und das selbe Konzept erfüllt. Guck dir an, wie in Ruby z.B. üblicherweise iteriert wird. Keine Iteratoren, sondern Closures.
So wie in meinem letzten Beispiel generische Polymorphie darüber hinweg geholfen hat spezielle Stacks, spezielle Queues, und so weiter zu implementieren helfen mir hier Closures darüber hinweg speziele Strategy-Hierarchienen spezielle Command-Hierarchienen, spezielle Iterator-Hierarchienen etc. zu implementieren.Schon mal über das Visitor Pattern in einer Sprache mit Multimehtoden/offenen Funktionen/wie auch immer die diversen Sprachen sie nennen nachgedacht? Ein unglaublich komplexes Konstrukt; dabei kann man multiple Dispatch auch auf deutlich einfachere Weise bekommen.
-
Fuer mich sind Pattern nur ein Sprachschatz. Es hilft beim erklaeren oder beschreiben eines Problems bzw. eher der Loesung eines Problems.
Wenn wir uns zB die C++ concept_map vorstellen, so ist das ein wunderschoenes Beispiel eines Adapters. Nur dass ich dann nie Adapter sagen wuerde, sondern einfach "concept_map".
Wenn die Sprache dieses Feature aber nicht direkt unterstuetzt, oder nicht alle Beteiligten mit diesem Sprachfeature vertraut sind, dann ist es praktisch zu sagen "wir verwenden hier einen Adapter".
IMHO machen viele Leute den Fehler und betrachten Design Pattern als Loesungen fuer Probleme - ich wuerde sie aber eher als Namen fuer abstrakte Loesungen betrachten. Denn ein Strategy in C++ sieht nunmal anders als in OCaml aus. Der Vorteil das Pattern Strategy hier zu verwenden liegt IMHO lediglich darin, dass ein aussenstehender (also jemand der nicht direkt in dem Programmiererteam sitzt das das Problem geloest haben) schnell das allgemeine Design verstehen kann.
Die Beispielimplementationen zu den Pattern geben lediglich eine Hilfestellung um das abstrakte Thema konkreter anfassen zu koennen.
-
Es ist egal, ob es in einer Sprache einfach oder kompliziert ist ein Pattern zu implementieren. Du löst das Problem trotzdem mit dem gleichen Muster, also mit diesem oder jenem Pattern. Die Patters wurden ja nicht mit OOP erfunden, bestimmte Probleme wurden auch schon vorher immer auf eine ähnliche Weise gelöst. Irgendwann kam halt die Idee auf, diesen einen Namen zu geben und sie allgemein zu beschreiben. Es geht nicht um Implementierungsdetails, sondern um die Idee. Dass sich die Idee ein Problem mit diesem Muster zu lösen, bei manchen Sprachen praktisch aufdrängt, ist genauso normal, wie dass man Patters zufällig implementiert, ohne das Pattern zu kennen.
-
Die Patters wurden ja nicht mit OOP erfunden
Doch. Wie willst du ein Singleton bauen, wenn es gar kein Objekt gibt? Wie viele der GoF Design Pattern machen Sinn, oder sind in welcher Form auch immer überhaupt umsetzbar, wenn es weder Klassen noch Objekte gibt?
Zitieren wir doch mal das GoF-Buch:
[quote"Design Pattern"]It's a book of design patterns that describes simple and elegant solutions to specific problems in objectoriented software design. Design pattern capture solutions that have developed and evolved over time. Hence they aren't the designs people tend to generate initially.[/quote]Ich denke es geht hier in etwa um folgende Fragen:
Ab wann ist etwas ein Design Pattern?Betrachten wir folgendes Pseudocode-Beispiel:
foo = 5 funktion(6)
Beinhaltet die erste Zeile das Zuweisungs-Design Pattern und die zweite das Funktionsafruf-Design Pattern? Oder sind diese Dinge zu trivial? Strategy und Command sind kein bischen komplizierter als diese Zuweisung. Mit kein bischen meine ich auch ziemlich genau kein bischen.
Ich nehme einfach mal an, dass du in meinem Minni-Beispiel keine Design-Probleme siehst. Genausowenig wie jemand von einem Designproblem spricht, wenn man einer Variable eine ganze Zahl zuweist, spricht auch niemand von einem Designproblem, wenn er einer Variable 'ne Closure zuweist. Mein Gott, es ist 'ne Zuweisung.
Niemand wäre je aufgefallen, dass es überhaupt "Designprobleme" bei soetwas wie Strategy oder Command geben könnte, wenn es keine Sprache gegeben hätte, denen gewisse Abstraktionsmechanismen fehlen.
Meiner Meinung nach muss etwas ausreichend Komplex sein, um es als Designproblem betrachten zu können. Erst dann kann ich anfangen darüber nachzudenken, wie ich dieses Problem lösen kann und vielleicht habe ich später einen ähnlichen Fall, der sich ähnlich Lösen lässt. Ich erkenne das Muster darin und mein erster Ansatz ist die Gemeinsamkeit auszulagern. Sollte das nicht gehen, weil es einfach keine Möglichkeit diese Gemeinsamkeit zu beschreiben, dann habe ich dennoch das Muster erkannt und kann diese Art von Probleme lösen, indem ich es immer wieder auf die selbe Art und Weise designe. Das könnte man Design Pattern nennen.
Wenn es aber um soetwas geht, wie eine Zuweisung. Dann sehe ich da das Konzept der Zuweisung und ich nenne es auch Zuweisung aber das ist kein Design Pattern. Genau so wenig ist eine Closure ein Design Pattern. Aus Meiner Sicht ist das "Strategy Pattern" einfach nur eine Anwendung einer Closure, sowie eine Zuweisung einer ganzen Zahl an eine Variable einfach nur eine Anwendung der Zuweisung ist.
Meine Ansicht ist: Ein Design Pattern betrifft immer das Design. Es ist etwas, über das ich mir vorher beim Designen gedanken machen muss. Wenn ich multiple Dispatch brauche und dazu das Visitor Pattern umsetzen will, dann hat das große Auswirkunge auf das Design. Ich muss accept-Methoden spendieren, usw. Einmal angewendet ist das ganze ziemlich hinderlich dabei die Klassenhierarchie zu erweitern.
Habe ich hingegen Multimethoden sieht das ganze anders aus. Das was vorher ein Design-Problem war ist plötzlich nicht mehr oder weniger Aufwendig als irgend eine x-belibige Methode zu schreiben.---------------
Es macht Sinn gewissen Konzepten Namen zu geben. Ich nenne einen Stack auch Stack. Ich nenne ein Array Array. Ich nenne eine Funktion Funktion. Ich nenne eine Singleton Singleton. Ich nenne eine Variable eine Variable.
Ab wann ist ein Konzept ein Design Pattern?
-
Das Singleton Pattern ist eine Lösung für Probleme bei denen es nur ein Objekt geben darf. Wenn du z.B. die Verteilung von begrenzen Ressourcen regeln willst, bietet sich ein Singleton an, damit nur ein Objekt die Ressourcen verteilt und nicht zuviele verteilt werden. Das es in dem Buch und in vielen anderen objektorientiert beschrieben ist, liegt wohl daran, dass das gerade modern ist. Ein Singleton ist nicht die oo Schreibweise für globale Variablen. Sinn des Singleton Patterns ist es auch nicht eine Vorschrift zu liefern, wie man Klassen schreiben muss, damit man nur eine Instanz erstellen kann. Wahrscheinlich kann man in einigen Sprachen trotzdem eine zweite Instanz erstellen, wenn man irgendwelche Mem-Copy und Casting Hacks verwendet. Man macht es aber nicht, weil es nicht dem Softwaredesign entspricht und dann die Software das Problem nicht mehr löst. Du kannst die Idee des Singletons auch implementieren, wenn du keine Klassen hast. Dann greifst du z.B. auf eine bestimmte Struktur nur über bestimmte Methoden zu und musst bei der Implementierung drauf achten, dass du es nicht anderst machst, obwohl es möglich wäre. Ist dann zwar nicht mehr so schön wie in Klassen verpackt, aber die gleiche Idee.
Ein Funktionsaufruf ist auch eine Lösung für bestimmte Probleme, z.B. gleichen Code an verschiedenen Stellen auszuführen, ohne ihn zu kopieren.
Das sind aber Probleme auf unterschiedlichen Ebenen. Bei einem Design Pattern steckt eine Idee auf Softwaredesignebene dahinter und nicht einfach nur eine Idee wie man etwas implementiert. Das man beschreibt, wie man sowas möglichst effizient und sauber implementiert, gehört halt dazu, wenn man Ideen liefert wie man sauber und verständlich designt. Eine gute Idee bringt halt nicht viel, wenn sie schlecht und kompliziert umgesetzt wird.
-
antwort schrieb:
Sinn des Singleton Patterns ist es auch nicht eine Vorschrift zu liefern, wie man Klassen schreiben muss, damit man nur eine Instanz erstellen kann.
Was wenn die Sprache das aber direkt unterstuetzt?
Genau darum geht es Helium ja, soweit ich ihn verstanden habe.
Meiner Meinung nach entsteht ein Design Pattern immer dann, wenn man ein Konzept in eine Sprache einbauen will, die diese nicht native beherrscht.
-
Es ist nicht der Sinn des Singleton Pattern eine solche Vorschrift zu liefern, also ist es egal ob eine Sprache es direkt unterstützt.
-
antwort schrieb:
Es ist nicht der Sinn des Singleton Pattern eine solche Vorschrift zu liefern, also ist es egal ob eine Sprache es direkt unterstützt.
Genau darum geht es aber - ist jedes Konzept ein Design Pattern?
Ist a=b; das Assignment Pattern?
-
Gucken wir uns doch einfach ein stückchen Code an:
foo ist eine Fuktion und ich übergebe ihr den Ausdruck 42:
-- Beispiel 1a foo 42
Wunderbar. Einfacher Funktionsaufruf. Nix besonderes. Nächstes Beispiel. bar ist eine Funktion und ich übergebe ihr den Ausdruck "42":
-- Beispiel 2a bar "42"
Hmm, ja nix neues. Weiteres Beispiel. baz ist eine Funktion und ich übergebe ihr den Ausdruck (42+):
-- Beispiel 3a baz (42+)
Hmm, ja und?. Irgendwie immer noch nichts neues. Es werden einfach Funktionen mit 'nem Argument aufgerufen.
Modifizieren wir die Beispiele ein kleines bischen. Statt das Argument direkt zu übergeben binde ich den Wert an eine Variable und übergebe die Variable:
-- Beispiel 1b tmp = 42 foo tmp
Toll. Code macht das selbe. Ist auch nix außergewöhnliches. Modifizieren wir das zweite Beispiel auf die selbe weise:
-- Beispiel 2b tmp = "42" bar tmp
Schön. Jetzt noch das letzte:
-- Beispiel 3b tmp = (42+) baz tmp
Ja, wunderbar. Langweilig. Ist doch immer das selbe. Ausdruck wird an Variable gebunden, Funktion wird mit Variable als Argument aufgerufen.
Nein Moment! Ist dir etwa nicht aufgefallen, dass Beispiel 3b etwas ganz anderes ist, als alle anderen? Beispiel 3b ist doch eine Anwendung des Command Patterns!
Ah ja ... WTF?
-
Beispiel 3b ist dann eine Anwendung des Command Patters, wenn sich dahinter dieses Befindet und damit ein Problem nach diesem Muster gelöst wird.
Nur weil man etwas so implementiert, dass es so aussieht wie ein Singleton, wird noch nicht die Idee dahinter verwendet, falls man es z.B. nur als Ersatz für eine einfache globale Variable nimmt.
-
Beschreibe mir das "Muster" mit deinen Worten und ich sage dir, ob es dieses "Muster" erfüllt.
Falls es in die Richtung geht, wie "the Command pattern is a design pattern in which objects are used to represent actions", dann erfüllt 3b definitiv dieses Muster. tmp ist genau dazu da die Aktion des Addierens von 42 zu einem belibigen Argument zu repräsentieren.
Fragt sich dann nur, warum es kein Pattern gibt, dessen Beschreibung in etwa lautet "the ... pattern is a design pattern in which objects are used to represent numbers" oder eins, dessen Beschreibung lautet "the ... pattern is a design pattern in which objects are used to represent text".
-
Mit dem Command Pattern kannst du die Ausführung der Aktion unabhängig vom Erstellen machen. Du fügst Aktion und Daten zu einer Einheit zusammen und kannst dann verschiedene Aktionen beliebig ordnen. Das mag vielleicht in einigen Sprachen einfach zu implementieren sein und dir trivial erscheinen, weil du die Idee kennst, aber es ist bei weitem nicht so trivial und allgemein wie "Objekt ist Nummer". Was sollen diese Objekt ist Nummer Patters für Designprobleme lösen? Das ist einfach so allgemein und doch irgendwie so eingeschränkt, dass ich da keine Idee sehe, die mir bei der Lösung einer Problemgruppe helfen würde.
-
antwort schrieb:
Mit dem Command Pattern kannst du die Ausführung der Aktion unabhängig vom Erstellen machen. Du fügst Aktion und Daten zu einer Einheit zusammen und kannst dann verschiedene Aktionen beliebig ordnen.
Das ist genau was
tmp = (42+) baz tmp
macht.
Beantworte mir deshalb folgende Frage:
a=b;
ist das das Assignment Pattern?
-
antwort schrieb:
Du fügst Aktion und Daten zu einer Einheit zusammen und kannst dann verschiedene Aktionen beliebig ordnen.
Du meinst eine Closure?
Das mag vielleicht in einigen Sprachen einfach zu implementieren sein und dir trivial erscheinen, weil du die Idee kennst, aber es ist bei weitem nicht so trivial und allgemein wie "Objekt ist Nummer".
Für mich ist die Aussage "Objekt ist Closure" tatsächlich nicht komplizierter als "Objekt ist Nummer".
Was sollen diese Objekt ist Nummer Patters für Designprobleme lösen?
Stell dir vor Zahlen wären nicht in die Spache eingebaut. Du würdest sie dir selbst bauen. Es könnte dann gängig sein, eine Enumeration mit genau zwei Zuständen zu bauen (quasi eigene Bits) und dann Arrays davon anzulegen mit einer bestimten Größe. So könnte man dann Zahlen darstellen. Ein Array von einer Enumeration die genau zwei zustände Annhemen kann wäre dann das "Objekt ist Nummer" Pattern.
Siehst du, sobald etwas nicht mehr trivial ist, aber immer wieder gebraucht wird wird es zum Design Pattern, auch das "Objekt ist Nummer" Pattern.
-
Helium schrieb:
Das mag vielleicht in einigen Sprachen einfach zu implementieren sein und dir trivial erscheinen, weil du die Idee kennst, aber es ist bei weitem nicht so trivial und allgemein wie "Objekt ist Nummer".
Für mich ist die Aussage "Objekt ist Closure" tatsächlich nicht komplizierter als "Objekt ist Nummer".
Die Idee ist aber komplizierter, auch wenn die Aussagen gleich klingen.
Mit Closures kannst du auch noch andere Sachen machen, als das Command Pattern umsetzen. Closures erklären dir nicht die Idee des Patterns. Nur weil du Closures kennst, musst du noch nicht auf die Idee kommen, sie so einzusetzen, dass du ein Problem mit diesem Pattern löst. Es ist zwar wahrscheinlich, dass du irgendwann auf die Idee kommst das Command Pattern zu implementieren, aber ich habs ja schon gesagt, man implementiert Patterns auch mal zufällig, auch wenn man sie nicht kennt.
Natürlich kannst du ein "Objekt ist Nummer" Patter definieren. So wie du es gemacht hast ist es zum einen unrealistisch, weil eine Sprache in der es keine Zahlen gibt auch keine Pointer hätte (Adressen sind auch Zahlen) und somit nichts im PC ansprechen könnte. Und ich seh auch nicht wirklich ein Muster für eine Problemgruppe, sondern einfach nur eine Lösung wie man Zahlen simulieren könnte.
Shade Of Mine schrieb:
a=b;
ist das das Assignment Pattern?
Und was soll die Idee hinter dem Assignment Pattern sein? Was für Designprobleme löst es? Ich seh da kein Muster das bestimmte Probleme löst. Es ist einfach so allgemein, dass es alles und nichts löst. Ein Pattern beschreibt ein Muster, mit dem man bestimmte Probleme softwaretechnisch lösen kann. Eine Zuweisung löst noch kein Problem.
-
man ist das hier wieder eine seltsame diskussion....
patterns sind viel mehr, als irgendwelche features, die in einer sprache fehlen...
würde echt gerne mal wissen, wie ihr das pipes and filters oder microkernel pattern als sprachfeature implementieren würdet. composite würde auch schon reichen...:D oder auch irgendwelche analysis patterns, wie z.b. accountabilitypatterns sind benennungen von lösungsansätzen für bestimmte, immer wieder auftretende einigermaßen komplexe probleme. es gibt beliebig viele möglichkeiten wie man solche patterns konkret umsetzt, es ist immer problem- und kontextabhängig. wer bspw. allgemeingültige patternbibliotheken schreibt, der hat nicht verstanden was ein pattern ist. es gibt sicherlich patterns, z.b. visitor, die in sprachen teilweise konkret unterstützt werden (multimethods). ein visitor kann aber auch viel mehr sein. ein SAX-handler ist z.b. doch auch nichts weiter als ein visitor, der den xml baum durchgeht. oder das command pattern: eine kleine erweiterung und du kannst mit dem command pattern active objects realisieren oder das "rückgängig machen" von aktionen. plötzlich hat das kaum was mit closures zu tun, oder? :-).