action() vector Document titel prompt shortCut 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() Menu action() add (Menu_Base*) remove(Menu_Base *) ItemOpenDoc action() Client Menu_Base vector titel, prompt, shortCut open() close() copy() paste() ItemCloseDoc action()">

Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

FB Informatik Prof. Dr. R.Nitsch Vorbereitung zu Praktikum 3 Menü-Toolkit und Command Pattern.

Ähnliche Präsentationen


Präsentation zum Thema: "FB Informatik Prof. Dr. R.Nitsch Vorbereitung zu Praktikum 3 Menü-Toolkit und Command Pattern."—  Präsentation transkript:

1 FB Informatik Prof. Dr. R.Nitsch Vorbereitung zu Praktikum 3 Menü-Toolkit und Command Pattern

2 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch Ein (schlechtes) Klassen Design Menü und Menüeinträge stehen in einer "part-of"-Beziehung (Aggregation). Application add(Document) Menu add(MenuItem) remove(MenuItem) action() Item_Taskx action() vector titel prompt shortCut item item->action() vector Document titel prompt shortCut 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() Menu action() add (Menu_Base*) remove(Menu_Base *) ItemOpenDoc action() Client Menu_Base vector titel, prompt, shortCut open() close() copy() paste() ItemCloseDoc action()

4 FB Informatik Prof. Dr. R.Nitsch Implementierungsansätze action()=0 offer() Menu action() add (MenuItem*) remove(MenuItem*) ItemTaskx action() Client Menu_Base 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 }; class Menu : public Menu_Base { vector _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 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch Teamwork Sequenzdiagramm der Objekte beim Command Pattern 1.Client (z.B. Managerklasse) erzeugt Command-Objekte und setzt den Receiver. 2.Client übergibt das Command-Objekt an den Aufrufer 3.Aufrufer fordert das Command-Objekt zur Ausführung des Befehls auf. 4.Das Command-Objekt befiehlt dem Receiver die in execute() codierte Aktion

12 FB Informatik Prof. Dr. R.Nitsch 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 FB Informatik Prof. Dr. R.Nitsch 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 add(Document) Menu add(MenuItem) remove(MenuItem) action() MenuItem action() vector item cmd->execute() vector Document Command* cmd open() close() copy() paste() Command execute() cmd


Herunterladen ppt "FB Informatik Prof. Dr. R.Nitsch Vorbereitung zu Praktikum 3 Menü-Toolkit und Command Pattern."

Ähnliche Präsentationen


Google-Anzeigen