Design-Pattern-Sammlung.
-
Ich wünsche mir eine Sammplung von Design-Pattern-Implementierungen in C++.
Diese sollten auch möglichst allgemeingültig sein.
Kam schonmal wer auf die Idee, sowas als Bibliothek zur Verfügung zu stellen?Ansonsten würd ich doch hier mal anfangen und hoffe auf rege Beteiligung.
Dies hier ist ein Command Pattern und eine dafür geeignete universelle Klasse.
als pData kann man dem Command beispielsweise einen Pointer auf eine Struct mit allen wichtigen Informationen geben.#ifndef COMMAND_H #define COMMAND_H #include <iostream> using namespace std; class command { protected: char *data; public: virtual void undoCommand(); virtual void doCommand(); command(char *pData); virtual ~command(); }; #endif // command.cpp: Implementierung der Klasse command. // ////////////////////////////////////////////////////////////////////// #include "command.h" ////////////////////////////////////////////////////////////////////// // Konstruktion/Destruktion ////////////////////////////////////////////////////////////////////// command::command(char *pData) { this->data = pData; } command::~command() { this->data = NULL; } void command::doCommand() { cout << "command done:" << this->data << endl; } void command::undoCommand() { cout << "command undone: " << this->data << endl; }
Man kann hier natürlich beliebige Ableitungen von schaffen. Die Grundimplementierung macht testweise Ausgaben.
Die commandHistory ist eine ensprechende Verwaltung des Ganzen:
// commandHistory.h: Schnittstelle für die Klasse commandHistory. // ////////////////////////////////////////////////////////////////////// #ifndef COMMANDHISTORY_H #define COMMANDHISTORY_H #include <vector> #include "command.h" using namespace std; class commandHistory { private: vector<command *> undoHistory, redoHistory; public: void delRedo(); void delUndo(); commandHistory(); virtual ~commandHistory(); void addCommand (command *); void undoCommand (void); void redoCommand (void); bool isUndoPossible (void); bool isRedoPossible (void); }; #endif // commandHistory.cpp: Implementierung der Klasse commandHistory. // ////////////////////////////////////////////////////////////////////// #include "commandHistory.h" commandHistory::commandHistory() { this->delRedo(); this->delUndo(); } commandHistory::~commandHistory() { this->delRedo(); this->delUndo(); } void commandHistory::addCommand (command *c) { this->delRedo(); // ist nicht mehr möglich, wenn ein neues Command kommt this->undoHistory.push_back(c); c->doCommand(); } void commandHistory::undoCommand (void) { command *c; c = *(this->undoHistory.end() - 1); this->undoHistory.pop_back(); this->redoHistory.push_back(c); c->undoCommand(); } void commandHistory::redoCommand (void) { command *c; c = *(this->redoHistory.end() - 1); this->redoHistory.pop_back(); this->undoHistory.push_back(c); c->doCommand(); } bool commandHistory::isUndoPossible (void) { return (this->undoHistory.size != 0); } bool commandHistory::isRedoPossible (void) { return (this->redoHistory.size != 0); } void commandHistory::delUndo(void) { vector<command*>::iterator it; for (it = this->undoHistory.begin(); it != this->undoHistory.end(); it++) { delete (*it); } this->undoHistory.clear(); } void commandHistory::delRedo(void) { vector<command*>::iterator it; for (it = this->redoHistory.begin(); it != this->redoHistory.end(); it++) { delete (*it); } this->redoHistory.clear(); }
Hier ein Testprogramm.
#include "commandHistory.h" int main (int argc, char *argv[]) { commandHistory *myHistory = new commandHistory; char data[] = "hallo"; char data2[] = "welt"; myHistory->addCommand(new command(data)); myHistory->undoCommand(); myHistory->redoCommand(); myHistory->addCommand(new command(data2)); myHistory->undoCommand(); myHistory->undoCommand(); myHistory->redoCommand(); delete myHistory; return 0; }
Etwas ähnliches nutze ich auch shcon in meinen aktuellen Programmen..
-
Vielleicht so etwas: http://home.earthlink.net/~huston2/dp/patterns.html
-
schon ganz interessant. Sind allerdings Beispielimplementierungen. Ich möchte eine allgemeingültige Bibliothek haben
-
Nimm Loki,
das ist die Bibliothek zu Modernes C++ Design | ISBN: 3826613473.
Dabei handelt es sich um
A C++ library of designs, containing flexible implementations of common design patterns and idioms.
Müsste genau das sein, was du suchst.
Habe mich aber selber nicht so genau damit beschäftigt, müsste aber hinkommen.
http://sourceforge.net/projects/loki-lib/
Felix
-
DocJunioR schrieb:
schon ganz interessant. Sind allerdings Beispielimplementierungen. Ich möchte eine allgemeingültige Bibliothek haben
Manager: "Ich brauche einen roten Dosenöffner!"
SW-Entwickler: "Hier hast einen grünen Dosenöffner!"
Manager: "Kann ich nicht gebrauchen. Damit bekomme ich nicht jede Dose auf!"Der hat auch nicht verstanden was ein Pattern ist ...
-
ich hab mehr als genug verstanden um zu wissen, wann ein kommentar sinnlos ist..
deiner war es..
-
ich hab mehr als genug verstanden um zu wissen, wann ein kommentar sinnlos ist..
deiner war es..Nein, war er ganz und gar nicht. Er wollte damit halt andeuten, wenn auch nicht auf ganz offensichtliche Art und Weise, dass dein Vorhaben nur geringfügig Sinn macht, weil eine "Bibliothek für Patterns" sich nur auf ganz wenige anwenden lässt.
Beispiel: Adapter-Pattern
Was willst du da anbieten, wenn du weder das zu adaptierende Interface, noch das adaptierte Interface kennst (und die kennst du eben in einer Bibliothek nicht)?Beispiel: Builder-Pattern
Wie willst du irgend ein Objekt erstellen, wenn du kein Interface kennst, mit den einzelnen Schritten die dazu nötig sind?Selbst dein Beispiel mit dem Command ist nur bedingt nützlich, da du eine nutzlose Basisklasse anbietest, in der du bereits viel zu viel vorgibst (Ausgabe bei jeder Operation und Datenhaltung, ist char* etwa Pflicht bei einem Command? ..) und einen Stack mit dem Namen CommandHistory ..
...
Hättest du mal lieber auf Prof84 gehört.
-
Nachtrag:
Wo wir derzeit beim Thema Design Patterns befinden, würd ich gern ein wenig Werbung für meine nächste Version der Bibliothek OOP++ machen. Sie liefert OOP in Form von einer Bibliothek aus, mit der neuesten Version 0.1 sind auch bereits erste Ansätze von Logik und mathematischem Verständniss implementiert.
-
Stud84 schrieb:
ich hab mehr als genug verstanden um zu wissen, wann ein kommentar sinnlos ist..
deiner war es..Nein, war er ganz und gar nicht. Er wollte damit halt andeuten, wenn auch nicht auf ganz offensichtliche Art und Weise, dass dein Vorhaben nur geringfügig Sinn macht, weil eine "Bibliothek für Patterns" sich nur auf ganz wenige anwenden lässt.
Teilsteils... Es gibt schon viele Patterns die man abstrakt formulieren kann nicht so wie du andeutest nur dieses eine
-
dali schrieb:
Stud84 schrieb:
ich hab mehr als genug verstanden um zu wissen, wann ein kommentar sinnlos ist..
deiner war es..Nein, war er ganz und gar nicht. Er wollte damit halt andeuten, wenn auch nicht auf ganz offensichtliche Art und Weise, dass dein Vorhaben nur geringfügig Sinn macht, weil eine "Bibliothek für Patterns" sich nur auf ganz wenige anwenden lässt.
Teilsteils... Es gibt schon viele Patterns die man abstrakt formulieren kann nicht so wie du andeutest nur dieses eine
Und welche? Der gesamte Loki-Port ist bei der Anwendung in Wirklichkeit nur eine Instanz!
Hier wäre Hume's Meinung sehr wertvoll ...
-
DocJunioR schrieb:
Ich wünsche mir eine Sammplung von Design-Pattern-Implementierungen in C++.
Diese sollten auch möglichst allgemeingültig sein.Wo steht, dass ich auf biegen und brechen alle Patterns umgesetzt haben möchte?
Außerdem: Was nützen mir tolle Vorlagen, wenn ich sie doch wieder eintippen muss?
Natürlich muss man sie immer etwas anpassen, aber die Basisklassen bleiben ja die Gleichen- und auch deren Nutzung..BTW: ich habe nie was gegen konstruktive Kritik. Allerdings find ich ehrlich gesagt in den letzten 2 Jahren einige Mitglieder dieses Forums zum K* * * *.
Dumme Sprüche klopfen wirkt vielleicht in nem B-Movie, aber in der Realität sollte man sich doch evtl. auf einen etwas freundlicheren Ton einigen.Wenn wir das Thema nun wieder sachlich aufgreifen würden. Bin ja immer bereit, dazu zu lernen..
-
Wo steht, dass ich auf biegen und brechen alle Patterns umgesetzt haben möchte?
Natürlich hast du nicht gesagt alle, aber darum gehts ja auch nicht. Es geht darum, dass du vielleicht 5 oder 6 Patterns, irgendsowas in der Größenordnung eben, in einer Bibliothek anbieten kannst, von über 25. Bei dieser Zählung hab ich aber schon mehr oder weniger nutzlose Implementierungen wie deine CommandHistory a.k.a. Stack mitgezählt.
Außerdem: Was nützen mir tolle Vorlagen, wenn ich sie doch wieder eintippen muss?
Was nützen mir tolle Taschenrechner, wenn ich doch wieder selbst denken muss?
Du hast einfach nicht verstanden, oder willst eben nicht verstehen, dass sich Design Patterns nicht mit in Bibliotheken zur Verfügung gestellten Komponenten oder Funktionen vergleichen lassen. Das sind vollkommen unterschiedliche Dinge, die auf einer ganz anderen Ebene der Programmierung abspielen.
-
der stack war garnicht das pattern das ich hier implementiert habe, sondern das Command Pattern..
-
der stack war garnicht das pattern das ich hier implementiert habe, sondern das Command Pattern..
Ach, die Klasse Comamnd ist also deine große Leistung? Ich will aber nicht zwangsweise char* für die Datenspeicherung benutzen müssen und ich will auch nicht, dass irgendwas ausgegeben wird. Denn dass sind bereits alles benutzerdefinierte Aktionen oder Eigenschaften, die das Command Pattern nicht vorschreibt.
So müsste das aussehen:
class Command { public: virtual void doCommand() = 0; virtual void undoCommand() = 0; virtual ~Command(); };
Was du also anbieten könntest, ist ein lediglich ein abstraktes Interface und genau deswegen werd ich mir auch eine zusätzliche Bibliothek dazulinken.
Womit wir wieder darauf zurückkommen, dass alles, was du anbieten kannst, ein Stack ist.
-
Prof84 schrieb:
Und welche? Der gesamte Loki-Port ist bei der Anwendung in Wirklichkeit nur eine Instanz!
Das hast Du prima erkannt, daß bei der Anwendung alles bloß instanziiert wird. Ist nur leider völlig irrelevant.
Loki bietet zum Beispiel eine Factory an, die recht allgemein geschrieben ist.
Dennoch stimmt es natürlich, daß Design-Patterns sich nicht in Bibliotheken gießen lassen (zumindest nicht in Code-Bibliotheken, viele UML-Tools können einem Standard-Patterns generieren).
-
Stud84 schrieb:
Ach, die Klasse Comamnd ist also deine große Leistung?
Also als Leistung hab ich's nicht gerade definiert. Immerhin sind das nur nen paar Zeilen, die man innerhalb einer halben Stunde runterbeten kann. Aber genau das will ich ja nicht immer wieder
Ich will aber nicht zwangsweise char* für die Datenspeicherung benutzen müssen und ich will auch nicht, dass irgendwas ausgegeben wird.
Du großer Meister wirst ja wohl casten können? Die Ausgabe ist auch nur ein Beispiel. Abgeleitete klassen werden diese Methoden einfach überschreiben und vergessen.
Was du also anbieten könntest, ist ein lediglich ein abstraktes Interface und genau deswegen werd ich mir auch eine zusätzliche Bibliothek dazulinken.
Womit wir wieder darauf zurückkommen, dass alles, was du anbieten kannst, ein Stack ist.
Endlich mal ein sachlich artikuliertes Argument..
Ich lass gern mit mir reden.
Wenn man sich übrigens die 2000 anderen Postings von mir anschaut, merkt man vielleicht, dass ich gelegentlich einfach nur Gedanken aufschreibe um die Meinung anderer zu hören.
Trotzdem find ich, dass das Forum wieder freundlicher werden könnte..
-
DocJunioR schrieb:
Du großer Meister wirst ja wohl casten können?
Warum sollte ich das überhaupt wollen? Warum sollte ich z.B: eine Zahl oder gar ein komplexeres Objekt als String abspeichern wollen? Natürlich muss ich das auch nicht, ich könnte es ja trotzdem in einem neuen eigenen Attribut dafür sichern, aber dann schlepp ich irgendwelche Altlasen mit mir her. Es ist einfach nicht generell, dass ich die Daten als char* speichern will, und demzufolge hat so ein Attribut auch nichts in einer generellen Klasse verloren.
DocJunioR schrieb:
Die Ausgabe ist auch nur ein Beispiel. Abgeleitete klassen werden diese Methoden einfach überschreiben und vergessen.
Es beginnt aber schon alleine damit zu behaupten, dass das Standartverhalten eines Commands die Ausgabe auf der Konsole ist, was einfach nicht stimmt. Noch dazu, wird man durch diese Standardimplementierung nichtmal dazu gezwungen diese Methode zu überschreiben, was dazu führen kann, dass man darauf vergisst.
Solltest du wirklich "Logging"-Funktionalität für deine Commands einbauen wollen, dann doch lieber so:
class LoggingCommand : public Command { private: Command& command; public: LoggingCommand(Command& command) : command(command) { // ... } void doCommand() { command.doCommand(); cout << "Command done." << endl; } void undoCommand() { command.undoCommand(); cout << "Command undone." << endl; } }
-
Das ist übrigens ein Beispiel für einen Dekorierer, ebenfalls ein Muster, das sich nicht allgemein implementieren läßt.