1 / 13

Vorbereitung zu Praktikum 3

Vorbereitung zu Praktikum 3. Menü-Toolkit und Command Pattern. Fallstudie zu Vererbung und Polymorphie: "Menü-Toolkit". Anwenderfreundliche Programme werden mit Menüs gesteuert In OO-Anwendungen werden Menüs und Menüeinträge durch Objekte repräsentiert.

zubeda
Télécharger la présentation

Vorbereitung zu Praktikum 3

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Vorbereitung zu Praktikum 3 Menü-Toolkit und Command Pattern

  2. Fallstudie zu Vererbung und Polymorphie: "Menü-Toolkit" • Anwenderfreundliche Programme werden mit Menüs gesteuert • In OO-Anwendungen werden Menüs und Menüeinträge durch Objekte repräsentiert. • Ein rudimentäres Menü (Objekt vom Typ Menu) besteht mindestens aus • einem Titel (z.B. Member titel vom Typ string) • mindestens einem Menüeintrag (jeder solcheEintrag ist selbst ein Objekt), • einer zugeordneten Aktion ( action() ), • die alle Menüeinträge anzeigt, • den Nutzer zur Auswahl auffordert (prompt) • die Nutzerauswahl entgegen nimmt (Maus-Click, Short-Cut), • und die den vom gewählten Eintrag angebotenen Service zur Ausführung bringt. * HAUPTMENÜ *c....Copy p....Paste u....Undo r....Redo Ihre Wahl? a

  3. Ein (schlechtes) Klassen Design • Menü und Menüeinträge stehen in einer "part-of"-Beziehung (Aggregation). Application Item_Taskx Menu item add(Document) action() add(MenuItem) remove(MenuItem) action() vector<Device> titel prompt shortCut vector<MenuItem> titel prompt shortCut Document open() close() copy() paste() item->action() Menu_Base Client • Durch Generalisierung der Klassen Menu und Item_Taskx erhält man diese Vererbungsstruktur. • offer() zeigt den Short-Cut und den Titel auf dem Display action()=0 offer() titel, prompt, shortCut Menu ItemOpenDoc action() action() add (Menu_Base*) remove(Menu_Base *) ItemCloseDoc action() vector< Menu_Base *>

  4. Implementierungsansätze class Menu_Base { protected: string _shortCut; string _titel; public: Menu_Base(const string& shortCut, const string& titel) : _shortCut(shortCut), _ titel(titel) { } virtual void action()=0; virtual void offer(); string getShortCut() const; // Accessor string getTitel() const; // Accessor }; Menu_Base Client action()=0 offer() Menu ItemTaskx action() add (MenuItem*) remove(MenuItem*) action() void Menu::action() { // Alle Menüeinträge auf dem Display anbieten // Dem User die Möglichkeit zur Auswahl bieten // Die Auswahl entgegen nehmen // Den ausgewählten Menüpunkt identifizieren // Für diesen Eintrag action() aufrufen // Fehlerbehandlung bei ungültiger Auswahl. } class Menu : public Menu_Base { vector<Menu_Base*> _menuComponents; char _itemSelector; string _prompt; public: Menu( const string& shortCut , const string& titel, const string& prompt ); virtual ~Menu(void); virtualvoid action(); virtual void add( Menu_Base* mb ); virtual void remove( Menu_Base* mb ); int size() const; int find( conststring& shortCut ); };

  5. Demo class ItemAddDevice : public Menu_Base { Receiver* _prcv; // -> receiver public: ItemAddDevice( const string& shortCut, const string& titel, Receiver *prcv ) : Menu_Base( shortCut, titel ), _prcv(prcv) {} virtual ~ItemAddDevice() {} virtualvoid action(); }; void ItemAddDevice::action() { // Hierher soll der gesamte Dialog mit dem Nutzer _psh->addDevice(); // Ab hier keine Eignung zum Toolkit }

  6. Demo void Menu::action() { // Menütitel ausgeben cout << _titel << endl; // Alle Menüeinträge auf dem Display anbieten _menuComponents[0]->offer(); // Dem User die Möglichkeit zur Auswahl bieten cout << _prompt; // Die Auswahl entgegen nehmen string selection; cin.clear(); cin.sync(); cin >> selection; // Den ausgewählten Menüpunkt identifizieren int index = find( selection ); // Für diesen Eintrag action() aufrufen this->_menuComponents[index]->action(); // Fehlerbehandlung bei ungültiger Auswahl. }

  7. Warum ist das ein schlechtes Klassendesign? • Ein Menü-Objekt verwaltet (Anmeldung, Abmeldung) seine Menü-Einträge in einem Feld. • Wird das Menü ausgewählt, so bietet seine Methode action() die Menüeinträge zur Auswahl an. • Jedem Menüeintrag ist eine eigene Klasse gewidmet (z.B. ItemOpenDoc oder ItemCloseDoc) die action() im Sinne ihrer Aufgabe redefiniert. • Problem: Klassenstruktur des Menü-Toolbox ist dann weitgehend von der speziellen Anwendung bestimmt, in der es eingesetzt wird, und müsste zudem bei jeder neuen Anforderung seitens der Anwendung geändert werden. • Als Toolkit bezeichnet man allge-mein eine Sammlung von Bibliotheken, Klassen und Schnittstellen, die das Erstellen von Computerprogrammen vereinfachen sollen. • Toolkits müssen nichts von den Anwendungen wissen, die sie benutzen, d.h. es bestehen keine Abhängigkeiten zwischen ihnen. • Anwendungen müssen dann nur die Schnittstelle des Toolkits (hier: Schnittstelle der Basisklasse Menu_Base) kennen, um sie benutzen zu können. Kernfrage: Wie soll ein Menüeintragsobjekt einen Service-Auftrag ausführen, ohne etwas über den Serviceerbringer oder die Service-Ausführung zu wissen?

  8. Das Command Pattern • Aufgaben • Service-Anforderungen an Objekte richten, ohne die Servicedetails und/oder den Empfänger der Anforderung zu kennen • Viele Funktionen können von unterschiedlichen Stellen aus aufgerufen werden, z.B. Menüeintrag, Button, Popup-Menü bei Rechtsklick, Tastaturkürzel • Soll jedesmal die Funktion dahinter implementiert werden? • Befehle sollen rückgängig gemacht werden können (Undo) oder sie sollen erneut ausgeführt werden können (Redo). • Wie kann man das speichern, wenn die Operationen eng mit den Objekten, die sie aufrufen, verbunden sind?

  9. Lösungskonzept • Den Befehl in einem Objekt kapseln! • Das Befehlsobjekt • kennt den Befehlsempfänger (Receiver) • kennt den von diesem auszuführenden Service (Aktion) • weiss auch wie die Aktion rückgängig zu machen ist (merkt sich z.B. den alten Zustand) • Vorteile • Ein und derselbe Befehl kann von mehreren Objekten aus aufgerufen werden. • Die Befehlsobjekte können • in einer Befehlshistorie gespeichert werden. • als Parameter wie andere Objekte herumgreicht werden, nachdem Sie erzeugt wurden. • Entkopplung von Aufrufer und Empfänger eines Befehls: Der Aufrufer braucht den Befehlsempfänger nicht zu kennen, sondern nur die Befehlsschnittstelle.

  10. Entwurfsmuster Command (Command Pattern) • Die abstrakte Klasse Command definiert das Interface zur Ausführung eines Befehls • ConcreteCommand (z.B. OpenCommand, CopyCommand) implementiert die execute()-Methode der Klasse Command so, dass der Receiver die gewünschte Aktion ausführt. • Der Client (meist eine Managerklasse) erzeugt ein ConcreteCommand-Objekt und weist ihm den Receiver zu. • Der Invoker (z.B. ein Menüobjekt) fordert sein Befehlsobjekt auf, den Receiver die bekannte Action ausführen zu lassen ( command[i].execute() ) • Der Receiver (Textdokument, Anwendung) weiß, wie die entsprechenden Operationen auszuführen sind. command

  11. Teamwork • Sequenzdiagramm der Objekte beim Command Pattern • Client (z.B. Managerklasse) erzeugt Command-Objekte und setzt den Receiver. • Client übergibt das Command-Objekt an den Aufrufer • Aufrufer fordert das Command-Objekt zur Ausführung des Befehls auf. • Das Command-Objekt befiehlt dem Receiver die in execute() codierte Aktion. 1. 2. 3. 4.

  12. Implementierungsfragen • Wie intelligent sollte ein Command sein?  • Ein Extrem: Ein Command delegiert die Befehlsausführung sofort an den Receiver. • Das andere Extrem: Ein Command (z.B. CopyCommand) implementiert alle anfallenden Aufgaben intern • Es liegt im Ermessen des Programmierers, ob er einen der Extremfälle oder irgendwo dazwischen programmiert. • Support für Undo und Redo     Dazu muss ConcreteCommand zusätzlichen Speicher reservieren:  • für das Receiver-Objekt • die der Receivermethode zu übergebenden Parameter • für die Orginal-Werte, die bei der Befehlsausführung ggf. geändert werden. • Wie vermeidet man Fehlerakkumulation beim Undo-Prozess? • indem das command-Objekt ausreichend Daten speichert, um den Orginalzustand wieder herzustellen.  • Benutze C++ Templates • um nicht für jede Kombination von Receiver und Aktion eine Command-Subklasse deklarieren zu müssen.

  13. Anwendung des Command Patterns beim Menu-Toolkit • Man braucht jetzt nur noch einen Datentyp MenuItem zur Repräsentation der Menüeinträge. • Beim Erzeugen eines MenuItem-Objekts durch die Application (=Client) wird ihm der Receiver bekannt gemacht. • Nachdem das Menü-Objekt die Benutzerauswahl kennt und das zugehörige MenuItem-Objekt identifiziert hat, fordert es dieses auf, bei seinem Receiver die Serviceaktion abzurufen. • Die abstrakte Klasse Command definiert für diesen Zweck eine einheitliche Schnittstelle in Form der Methode execute() • Von Command abgeleitete Klassen (z.B. CommandOpen, CommandCopy, ...) redefinieren diese Methode und delegieren dabei ihrerseits die übernommene Aufgabe an den dafür vorgesehenen Receiver. Application Command MenuItem Menu item cmd execute() add(Document) action() add(MenuItem) remove(MenuItem) action() vector<Document> Command* cmd Document vector<MenuItem> open() close() copy() paste() cmd->execute()

More Related