Welche Design Patterns sollte man kennen?
-
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? :-).
-
Ich möchte mich mach 5 Jahren "Drauflosprogrammieren" gerne mal mit diesen "Design Patterns" auseinandersetzen. Gibt es irgendwo eine Liste mit allen "Design Patterns" incl. Beispiele?
-
excited boy schrieb:
Ich möchte mich mach 5 Jahren "Drauflosprogrammieren" gerne mal mit diesen "Design Patterns" auseinandersetzen. Gibt es irgendwo eine Liste mit allen "Design Patterns" incl. Beispiele?
Auf Wikipedia gibts eine kleine Übersicht
-
-
antwort schrieb:
Mit Closures kannst du auch noch andere Sachen machen, als das Command Pattern umsetzen. Closures erklären dir nicht die Idee des Patterns.
Closures machen das Pattern unnoetig.
In einer Sprache die Closures kann wirst du nie in die Verlegenheit kommen dir ein Pattern wie Command auszudenken, weil es einfach total natuerlich ist.
Wikipedia sagtIn object-oriented programming, the Command pattern is a design pattern in which objects are used to represent actions. A command object encapsulates an action and its parameters.
Genau das ist ein Closure. Genau das macht ein Closure.
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.
Und genau hier haengen wir. Es loest das Allgemeine Problem dass ich Daten kopieren will.
Zu allgemein? Aber was ist zu allgemein?
Command ist zB mit Closures einfach trivial. Du musst nichts kapseln, du machst lediglich closure-Zuweisungen, mehr nicht.Jedes Pattern kann man so reduzieren. Beispiel Visitor. Wenn die Sprache eine Klasse einfach fuer Erweiterungen oeffnet, ist das komplette Pattern unnoetig weil trivial durch eine Funktionsdefinition zu implementieren.
Wo trennt man hier. Ab wann ist etwas zu trivial? Genau da scheitern IMHO die meisten Leute an Pattern. Wenn die Sprache das Konzept unterstuetzt, wird das Pattern nie entstehen. Deshalb gibt es kein Assignment Pattern.
Aber dazu muss man mal mit solchen Sprachen gearbeitet haben um das zu verstehen. Pattern geben Konzepten die die Sprache nicht direkt Unterstuetzt einen Namen - mehr nicht. Man koennte das Command Pattern auch Closure-Pattern nennen - nur wuerde das nicht ganz stimmen weil Closures einfach unendlich maechtiger sind als das Command Pattern. Command ist etwas das man mit Closures ohne Probleme machen kann.
-
antwort schrieb:
Natürlich kannst du ein "Objekt ist Nummer" Patter definieren. So wie du es gemacht hast ist es zum einen unrealistisch
Aha. Eine Sprache in der es exakt 100%ig so gemacht wird, wie von mir beschreiben existiert aber. Sie ist ansonsten Java recht ähnlich. Du musst dir das entsprechende Paper aber selbst raussuchen, weil ich da gerade echt keinen Bock zu habe.
Und ich seh auch nicht wirklich ein Muster für eine Problemgruppe, sondern einfach nur eine Lösung wie man Zahlen simulieren könnte.
Genau so sehe ich im Command Pattern keine Lösung für ein Problem. Ich sehe einfach nur eine Lösung, wie man in einigen Situationen Closures simulieren könnte. Aber bevor du überhaupt jemals mit Closures gearbeitet hast werde ich nicht mehr weiter darüber sprechen.
oder das "rückgängig machen" von aktionen. plötzlich hat das kaum was mit closures zu tun, oder? :-).
Du meinst ich pack in 'ne Liste Closures rein, die die gemachten Aktionen Rückgängig machen? Und wenn ich auch noch ein Wiederherstellen haben will, dann pack ich in die Liste paarweise auch noch die Closures, die die eigentliche Aktion durchgeführt haben, so dass ich beliebig vor und zurück kann?
@patternfreak: Moment, moment, wir reden hier von klassischen Design Pattern, nicht von Architectural Pattern. IMO sind die beiden zu trennen. Du hätest vielleicht Model-View-Controller nennen sollen, als Beispiel, was wohl jeder hier kennt, also die grundlegende Überlegung die Daten von deren Darstellung zu trennen. Oder damit die Leute, die nichts mit Architectural Pattern anfangen können, wissen, wie allgemein Architectual Pattern sind, vielleicht einfach Peer-to-Peer.
Wenn ich in 'ner Shell ein paar Programme zusammenhänge, wie grep ... | sort | uniq dann habe ich schon das Architectural Pattern "pipes and filters" erfüllt. Aber ich erfülle es auch, wenn ich mit dem o Operator ein bischen Funktionskomposition betreibe. Das ist IMO etwas Grundlegend anderes, als z.B. das Command Pattern.
Und ich stimme dir 100%ig zu, dass Architectural Pattern nichts sind, was auf fehlende Sprachfeatures hindeutet.
-
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.
interessant wirds bei
a=a; //Selbstzuweisung
weiß allerdings nicht, ob es dafür ein entsprechendes Pattern gibt, bzw. ob sowas überhaupt über ein Pattern gelöst werden muss
-
Das ist doch das SelfAssignmentPattern
-
Shade Of Mine schrieb:
Man koennte das Command Pattern auch Closure-Pattern nennen - nur wuerde das nicht ganz stimmen weil Closures einfach unendlich maechtiger sind als das Command Pattern.
Merkst du was? Closures sind nicht das Command Pattern. Das Command Pattern ist kein Ersatz für Closures.
Helium schrieb:
Und ich seh auch nicht wirklich ein Muster für eine Problemgruppe, sondern einfach nur eine Lösung wie man Zahlen simulieren könnte.
Genau so sehe ich im Command Pattern keine Lösung für ein Problem. Ich sehe einfach nur eine Lösung, wie man in einigen Situationen Closures simulieren könnte.
...oder das "rückgängig machen" von aktionen. plötzlich hat das kaum was mit closures zu tun, oder? :-).
Du meinst ich pack in 'ne Liste Closures rein, die die gemachten Aktionen Rückgängig machen? Und wenn ich auch noch ein Wiederherstellen haben will, dann pack ich in die Liste paarweise auch noch die Closures, die die eigentliche Aktion durchgeführt haben, so dass ich beliebig vor und zurück kann?
Bist du dir wirklich sicher, dass du das Command Patter richtig verstanden hast?
Das Command Pattern ist mehr als der erste Satz aus dem Wikipedia Artikel.
-
Das Original schrieb:
Intent: Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support unduable operations.
Eine Closure ist doch ein gepaseltes Request.
Applicability:
[und jetzt fasse ich die Absätze mal ein bischen zusammen.]
- Als callbacks.
- Requests zu verschiedenen Zeitpunkten spezifizieren, einreihen ("queue") und ausführen. Ein Command Objekt hat eine Lebenszeit unabhängig vom ursprünglichen Request.
- Undo-Funktionalität.
- Aktionen mitloggen, so dass man sie später nochmals ausführen kann.Also für mich sieht es so aus, als könnte ich das, was Gamma, Helm, Johnson und Vilssides so an Anwendungsfällen gebracht haben, deutlich einfacher, übersichtlicher und leichter verständlich mit Closures erledigen.
IMO gibts auch keine besonderen Sachverhalte in Programmen, die man genauer spezifiziert, wenn man sagt: Da setze ich das Command Pattern um.Aber nimm doch einfach ein Beispiel aus irgend einem deiner Projekte. Schreib dann einen Teil der das Command Pattern umsetzt mal so um, dass er Closures verwendet. Dann guck dir den Code an und überlege ob jemandem die Aussage "Das ist eine Umsetzung des Command Patterns" dabei helfen könnte diesen Code zu verstehen.
Nur so ne Anmerkung am Rande: Ich fand die Design Pattern früher auch mal ganz toll.
-
Ich fand und finde Design Patterns nicht ganz super toll. Sind ganz nützliche Ideen, aber nicht das ein und alles. Aber Design Patterns sind halt kein Ersatz für fehlende Sprachmittel. Und, dass das Command Pattern kein "Closure-Pattern" ist hat ja jetzt auch schon Shade Of Mine gesagt.
-
antwort schrieb:
Shade Of Mine schrieb:
Man koennte das Command Pattern auch Closure-Pattern nennen - nur wuerde das nicht ganz stimmen weil Closures einfach unendlich maechtiger sind als das Command Pattern.
Merkst du was? Closures sind nicht das Command Pattern. Das Command Pattern ist kein Ersatz für Closures.
...sondern nur eine Annaeherung an eine real existierende, elegantere Loesung. Die leider in der Zielsprache nicht verfuegbar ist.
-
ehrlich gesagt find ich das command pattern eleganter als closures, da es eben (nahezu) unabhängig von sprachmitteln ist.
-
Das wichtigste Anti-Pattern das man kennen sollte:
Das "Rechthaben"-Pattern.
Typische Merkmale dieses Patterns sind ständige Wiederholung der eigenen Meinung mit ständig leichten Variationen so wie der Zwang alle "Andersdenkenden" von ihren offensichtlichen Fehlern überzeugen zu müssen.
Zusätzlich werden alle Postings, die eine andere oder alternative Meinung darstellen grundsätzlich soweit falsch verstanden das man wieder dagegen argumentieren kann.
Wenn es nicht anders geht werden zusätzlich fiktive Argumente erfunden.
Das (unerreichbare) Ziel dieses Antipattern besteht darin auch den letzten Widersacher entweder zu überzeugen oder mundtod zu reden.
Die Möglichkeit, den eigenen Standtpunkt zu überdenken und auf Fehler hin zu betrachten wird von vorneherein abgetan, denn das wäre ja unsinnig, denn man hat ja Recht.
Typisches Anwendungsbeispiel des "Rechthaben" - Patterns:
A) Du musst auch immer das letzte Wort haben.
Nein, das tue ich nicht
A) Siehst Du, Du tuest es schon wieder.
Stimmt doch gar nicht.
A) Das lass es doch.
Aber ich mache es doch gar nicht.
A) Gerade hast Du es aber schon weider getan.
Stimmt nicht, Du hast doch das letzte Wort
A) [...]
-
Apollon schrieb:
antwort schrieb:
Shade Of Mine schrieb:
Man koennte das Command Pattern auch Closure-Pattern nennen - nur wuerde das nicht ganz stimmen weil Closures einfach unendlich maechtiger sind als das Command Pattern.
Merkst du was? Closures sind nicht das Command Pattern. Das Command Pattern ist kein Ersatz für Closures.
...sondern nur eine Annaeherung an eine real existierende, elegantere Loesung. Die leider in der Zielsprache nicht verfuegbar ist.
Mal abgesehen davon, ob Closures das Command Pattern ersetzen oder nicht. Vielleicht fehlt mir ja die Erfahrung, aber mir fällt da nix ein, was Closures da viel einfacher machen würden. Wie kann man denn mit Closures ein entsprechendes Problem einfacher und eleganter lösen, als mit ner einfachen OO Sprache und dem Command Pattern?
Beispiel:
Es sollen Projekte mit einer beliebiger Struktur aus Verzeichnissen und Dateien erstellt werden können. Jede Aktion soll geloggt werden. Die Projekte sollen zu irgendeinem Zeitpunkt erstellt werden. Wenn das Erstellen eines Projekts fehl schlägt, soll es möglich sein, dass das ganze Projekt wieder gelöscht wird.Java/Pseudocode Lösung:
public interface ICommand { boolean exec(); void undo(); } public class CreateDirCommand implements ICommand { private String name; public CreateDirCommand(String name) { this.name = name; } public boolean exec() { boolean success = CreateDir(name); if(success) LOG("Created dir: " + name); else LOG("Failed to create dir: " + name); return success; } public void undo() { DeleteDir(name); LOG("Deleted dir: " + name); } } public class CopyFileCommand implements ICommand { //Ähnlich wie oben } public class CreateProjectCommand implements ICommand { private List cmds = new LinkedList(); private Stack undoStack = new Stack(); void addCmd(ICommand cmd){ cmds.add(cmd); } public boolean exec() { for (Iterator iter = cmds.iterator(); iter.hasNext();) { ICommand cmd = (ICommand) iter.next(); undoStack.push(cmd); if(!cmd.exec()) { LOG("Failed to create project "); return false; } } LOG("Created Project"); return true; } public void undo() { while(!undoStack.isEmpty()) { ICommand cmd = (ICommand) undoStack.pop(); cmd.undo(); } LOG("Deleted Project"); } } ... void createExampleProject() { ... CreateProjectCommand projectCmd = new CreateProjectCommand(); projectCmd.addCmd(new CreateDirCommand("...src")); projectCmd.addCmd(new CreateDirCommand("...resources")); projectCmd.addCmd(new CreateDirCommand("...resources/images")); projectCmd.addCmd(new CopyFileCommand("defaultIcon.ico","...resources/images/projectIcon.ico")); saveSomeWhere(projectCmd); ... } public class Foo { public void onCreateProjectEvent(ICommand cmd) { if(!cmd.exec() && userWantsUndo) { cmd.undo(); } } }
Wie löst man das Problem jetzt mit Closures eleganter und/oder einfacher?
-
Statt der kompletten Klasse hast du eine liste. Eine Liste voller Closures.
Das lustige daran ist, du bist nicht an das ICommand interface gebunden, jede Funktion kannst du in das CreateProjectCommand stecken. Vorallem ist CreateProjectCommand somit selbst nur eine liste.
Und du kannst die Funktionen direkt dort definieren wo du sie in die CreateProjectCommand liste reinwirfst.
Du hast hier uebrigens 2 Design Pattern gemixt. CreateProjectCommand ist ein Composite - deshalb ist die Loesung mit closures hier nicht 100% straight forward.
-
antwort schrieb:
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.
Lustige Diskussion.
mal das Beispiel die Java-Sprache, dort gibt es keine globalen Variablen, also nimmt man das Singleton-Pattern um diese zu simulieren/ersetzen. Und schon haben wir ein Beispiel, wie ein Design-Pattern ein Sprachfeature ersetzt.
-
Shade Of Mine schrieb:
Statt der kompletten Klasse hast du eine liste. Eine Liste voller Closures.
Das lustige daran ist, du bist nicht an das ICommand interface gebunden, jede Funktion kannst du in das CreateProjectCommand stecken. Vorallem ist CreateProjectCommand somit selbst nur eine liste.
Ob es ein Vorteil ist, dass Interface weg zu lassen, weiß ich nicht.
Was du mit statt der Klasse nur ne Liste meinst, kann ich mir jetzt nicht vorstellen. Schreib doch mal den Code dazu mit der Undo-Funktionalität.Und du kannst die Funktionen direkt dort definieren wo du sie in die CreateProjectCommand liste reinwirfst.
Sowas in der Art?
projectCmd.addCmd(new ICommand() { public boolean exec() { Create... LOG... } public void undo() { ... } });
Führt doch nur zu Code duplication, wenn du die Funktion immer wieder hinschreibst, oder versteh ich was falsch?
Mach doch mal ein Beispiel.
DEvent schrieb:
antwort schrieb:
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.
Lustige Diskussion.
mal das Beispiel die Java-Sprache, dort gibt es keine globalen Variablen, also nimmt man das Singleton-Pattern um diese zu simulieren/ersetzen. Und schon haben wir ein Beispiel, wie ein Design-Pattern ein Sprachfeature ersetzt.
Du hast den Sinn des Singleton Patterns nicht verstanden.
Wenn du nur eine globale Variable brauchst, warum baust du dann ein Singleton darum?public class Global { public static int var; }
Tuts auch
-
Man könnte die Objekte einfach mit Closures nachbauen ("Closures sind die Objekte des armen Mannes und Objekte sind die Closures des armen Mannes.")
let createDir name = let doFun () = let success = CreateDir(name) in ( if success then LOG("Created dir: " + name) else LOG("Failed to create dir: " + name); success) let undoFun () = ... in (doFun, undoFun);; let copyFile name = ... //Ähnlich wie oben
Moment, "Ähnlich wie oben" klingt gar nicht gut. Scheint so, als hätten wir vergessen was auszulagern. Also nochmal von vorne.
let createSimpleCommand args action undoAction actionName = let doFun () = let success = action(args) in ( if success then log(actionName + " succeded") else log(actionName + " failed"); success) in let undoFun () = undoAction(args); log (actionName + " undone") in (doFun, undoFun);; let createDir name = createSimpleCommand name CreateDir DeleteDir ("create dir " + name);; let copyFile (source, target) = createSimpleCommand (source, target) CopyFile (snd >> DeleteFile) ("copy file from " + source + " to " + target);;
Gut, weiter
let createProject cmdList = let stack = new Stack<(unit->unit)>() in let doFun () = ... in let undoFun () = ... in (doFun, undoFun);; let createExampleProject() = ... let projectCmd = createProject [ createDir "...src"; createDir "...resources"; createDir "...resources/images"; copyFile ("defaultIcon.ico","...resources/images/projectIcon.ico")] in saveSomeWhere projectCmd; ... ;;
Aber das ganze gefällt nicht.
Beim Implementieren von createProject ist etwas aufgefallen: Es kann sein, das Aktionen mittendrin fehlschlagen. Dann braucht man eine passende Undo-Funktion, die nur den Teil rückgängig macht, der auch durchgeführt wurde. Man braucht also offensichtlich zu jeder Ausführung einer Aktion ein passendes Undo.
Außerdem fällt generell auf, dass das System es zulassen würde Aktionen rückgängig zu machen, ohne sie jemals ausgeführt zu haben. Kann man das nicht so umgestallten, dass es bereits zur Compilezeit ausgeschlossen ist?Schlagen wir beide Fliegen mit einer Klappe: Ein Kommando generiert als Rückgabe eine passende undo-Funktion, die genau das Rückgängig macht, was ausgeführt wurde. So kann man erst dann etwas Rückgängig machen wenn es auch ausgeführt wurde. (Nebenbei werden wir automatisch auch noch den State des CreateProjectCommand losgeworden.)
Der Umbau ist ja mehr oder weniger trivial. undoFun in die doFun verlegen, neben dem success auch noch die undoFun zurückgeben, statt des Tupels einfach nur die doFun liefern, bzw. sich das sparen und einfach die ganze create... ne annonyme Funktion zurückgeben lassen.let createSimpleCommand args action undoAction actionName = fun () -> let undoFun () = undoAction(args); log (actionName + " undone") in let success = action(args) in if success then ( log(actionName + " succeded"); (success, undoFun)) else ( log(actionName + " failed"); (success, id));;
createDir, copyFile, und mögliche andere Funktionen, die wir mittels createSimpleCommand erzeugt haben bleiben wie sie sind (Gott sei dank haben wir ausgelagert). createProject muss natürlich etwas mehr überarbeitet werden, wie alles, was mit den neuen Commands arbeitet.
Und bei der Implementierung von createProject werden Closures auf einmal richtig nützlich werden.
Ich reich die Implementierung noch nach, bin aber gerade ein wenig schreibfaul, bzw. habe jetzt schon viel zu viel geschrieben. Jaja, ich weiß, genau der spanende Teil fehlt ... aber man soll doch aufhören, wenns am schönsten ist. Wer aufgepast hat hat aber gemerkt, dass ich die Vorzüge schon angewendet habe beim verwenden von createSimpleCommand.