Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Vorbereitung zu Praktikum 3

Ähnliche Präsentationen


Präsentation zum Thema: "Vorbereitung zu Praktikum 3"—  Präsentation transkript:

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 solche Eintrag 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 Menu Item_Taskx item add(Document) add(MenuItem) remove(MenuItem) action() action() vector<Device> titel prompt shortCut Document vector<MenuItem> titel prompt shortCut open() close() copy() paste() item->action() Client Menu_Base 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 ItemOpenDoc Menu 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 }; Client Menu_Base action()=0 offer() ItemTaskx Menu action() action() add (MenuItem*) remove(MenuItem*) 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); virtual void action(); virtual void add( Menu_Base* mb ); virtual void remove( Menu_Base* mb ); int size() const; int find( const string& shortCut ); }; 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. }

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() {} virtual void 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.

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. 4. 3.

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
Application Menu MenuItem Command item cmd add(Document) add(MenuItem) remove(MenuItem) action() action() execute() vector<Document> Command* cmd Document vector<MenuItem> open() close() copy() paste() cmd->execute() 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.


Herunterladen ppt "Vorbereitung zu Praktikum 3"

Ähnliche Präsentationen


Google-Anzeigen