gespeichert zum

Werbung
Prof. Dr. Wilhelm Schäfer
Julian Suck
Sebastian Goschin
Moritz Schraut
Paderborn, 28. Oktober 2011
Besprechung der Aufgaben: 7. November 2011
Übungsaufgaben zur Vorlesung
Modellbasierte Softwareentwicklung
Wintersemester 2011/2012
Übungsblatt 3
Bitte beachten: Punkte für einen Bonusschritt können Sie auf diesem Zettel durch die Abgabe von Aufgabe 4 sammeln. Geben Sie Ihre Lösung in Papierform (inkl. ÜbungsgruppenNr.
und aller MatrikelNr.) in den D3-Zettelkasten und per E-Mail an [email protected] (Betreff: Blatt3 - GruppeX - MatrikelNr1, MatrikelNr2, ...“) ab. Bitte beachten Sie hierzu die
”
auf der Webseite aufgeführten Regeln.
Die Abgabe muss bis zum 7. November 2011 um 8.00 (s.t.) Uhr erfolgen!
Aufgabe 1 – Entwurfsmuster Adapter and Brücke
Die Entwurfsmuster Adapter und Brücke (Bridge) haben eine sehr ähnliche Struktur. Erklären Sie die Unterschiede zwischen beiden Mustern und veranschaulichen Sie, in welchen
Situationen sie genutzt werden. Finden Sie mindestens ein Beispiel pro Muster.
Aufgabe 2 – Suche im Baum
Modellieren Sie eine Baumstruktur in einem Klassendiagramm. Dabei soll es möglich sein,
schnell neue Baumstrukturen zu konstruieren, indem Knoten und andere Baumstrukturen
zusammengesetzt werden (s. Abbildung 1). Jeder Knoten enthält einen Integer. Zusätzliche
Blätter und innere Knoten sollen unterscheidbar sein. Innere Knoten können beliebig viele
Kinder haben. Zusätzlich sollte jeder Knoten die Summe seines eigenen Wertes und der Werte
seiner Kinder berechnen und zurück geben können.
12
12
7
23
5
47
11
7
21
23
5
47
11
21
Abbildung 1: Zusammensetzen einer Baumstruktur
a) Erstellen Sie unter Verwendung eines Entwurfsmusters ein Klassendiagramm, welches
die Baumstruktur beschreibt.
b) Nun soll ein bestimmter Wert im Baum gesucht werden. Fügen Sie Ihrem Design eine
Tiefen- und eine Breitensuche hinzu. Die Suche soll die Menge von Knoten zurück
geben, die den gesuchten Wert enthalten. Nutzen Sie wiederum Entwurfsmuster, wo es
sinnvoll ist.
1
c) Erklären Sie was die Methoden in ihrem Design tun. (Aufruf anderer Methoden usw.).
Aufgabe 3 – Das Decorator Pattern
Gelegentlich soll die Funktionalität einzelner Objekte erweitert werden, ohne ihre Klassen
zu ändern. Zum Beispiel können die Ordner-Icons in der Navigator-Ansicht in Eclipse mit
verschiedenen Symbolen versehen werden, die spezifische Attribute von Projekten visualisieren. Ist ein Projekt beispielsweise in einem Repository gespeichert, so erscheint ein kleiner
Zylinder rechts unten am Ordner Icon.
Vererbung ist eine Möglichkeit, diese Funktionalität zu implementieren. Dann müssten allerdings für sämtliche Kombinationen von Symbolen für Ordner Icons eigene Klassen angelegt
werden. Kommt ein weiteres Symbol hinzu, müssen sehr viele Klassen, die Kombinationen
von Symbolen repräsentieren geändert werden.
Ein flexiblerer Ansatz besteht darin, das Ordner Icon in einem anderen Objekt einzuschließen, das die Symbole hinzufügt. Das einschließende Objekt heißt Dekorierer (eng. Decorator).
Die Schnittstelle des Dekorierers entspricht der Schnittstelle der dekorierten Komponente, so
dass seine Anwesenheit für benutzende Klassen transparent ist. Der Dekorierer leitet Methodenaufrufe an die Komponente weiter und führt möglicherweise vor oder nach dem Weiterleiten zusätzliche Operationen aus, wie zum Beispiel das Dekorieren des Ordner Icons mit
einem Symbol und das anschließende Rendern. Diese Transparenz ermöglicht es, Dekorierer
rekursiv zu schachteln. Somit kann beliebige und mengenmäßig unbeschränkte Funktionalität
hinzugefügt werden.
Component
+operation()
*
*
ConcreteComponent
Decorator
-component
+operation()
+operation()
ConcreteDecoratorA
component -> operation()
ConcreteDecoratorB
-addedState
+operation()
+operation()
+addedBehavior()
Decorator.operation();
addedBehavior();
Abbildung 2: Struktur des Decorator Pattern
Das Decorator Pattern (s. Abbildung 2) bietet also eine flexible Alternative zur Unterklassenbildung, um die Funktionalität einer Klasse zu erweitern.
Vergleichen Sie das Decorator Pattern mit den folgenden drei Pattern: Adapter, Composite
und Strategy Pattern. Was sind jeweils die markanten Unterschiede?
2
Aufgabe 4 – Das Visitor Pattern
(Korrekturaufgabe, 6 Punkte)
Das Klassendiagramm in Abbildung 3 beschreibt Formeln einer Prädikatenlogik. Alle Teilformeln erben von der abstrakten Klasse Formula. Die Logik besteht aus atomaren Formeln,
die durch die Klasse AtomicFormula repräsentiert werden. Atomare Formeln sind unäre oder
binäre Prädikate wie beispielsweise istGerade(x) oder kleiner(y, 2). Der Name eines Prädikats wird im Attribut name gespeichert. Die Argumente der Prädikate sind Terme, die durch
die abstrakte Klasse Term repräsentiert werden. Terme wiederum können Variablen wie beispiesweise x, y, . . . oder Konstanten wie 1, 2, true, 2.56, . . . sein. Die konkrete textuelle Darstellung einer Variablen bzw. einer Konstanten wird im Attribut name gespeichert.
Atomare Formeln können durch unäre Operatoren (UnaryOperator) oder binäre Operatoren (BinaryOperator) zu komplexeren Formeln kombiniert werden. Unter den unären
Operatoren gibt es zum einen die aus der booleschen Logik bekannte Negation (¬, Negation).
Die Teilformel, die negiert wird, wird über die Assoziation subFormula gespeichert. Zum
anderen existieren Quantoren (Quantifier), die das Quantifizieren über Variablen ermöglichen. Hierbei wird zwischen dem Existenzquantor (∃, Existential) und dem Allquantor (∀,
Universal) unterschieden. Die Variable, über die quantifiziert wird, wird über die Assoziation
has gespeichert, die zugehörige Teilformel wieder über die Assoziation subFormula.
Die binären Operatoren bestehen aus der Konjunktion (∧, Conjunction), der Disjunktion (∨, Disjunction) und der Implikation (→, Implication). Diese speichern die beiden Teilformeln, die sie verbinden, jeweils über die Assoziationen firstSubFormula und
secondSubFormula.
Abbildung 3: Klassendiagramm einer Prädikatenlogik
4.1 Auf der Web-Seite steht das Klassendiagramm als Fujaba-Projekt-Datei zur Verfügung
(predicateLogic.fpr.gz). Generieren Sie zunächst den Quell-Code! Bauen Sie anschließend
zwei Objektstrukturen auf, die jeweils die Formeln ¬(∃x(istGerade(x) ∧ kleiner(x, 2))) und
∀x(∃y(istGrößer(x, y))) repräsentieren! (Abgabe: kommentierter Quelltext)
3
4.2 Überlegen Sie sich eine sinnvolle, auf einem Rechner darstellbare Infix-Notation für
jede der Teilformeln. Fügen sie der Klasse Formula eine Methode toString() hinzu und implementieren Sie diese entsprechend der gewählten Notation für jede der Teilformeln! Beim
Aufruf der toString()-Methode soll der gesamte Teilbaum unterhalb der Formel traversiert und alle enthaltenen Teilformeln mit berücksichtigt werden! Geben sie mit Hilfe der
toString()-Methode die textuellen Darstellungen der beiden Formeln aus der vorherigen
Aufgabe aus! (Abgabe: Erklärung der Notation, kommentierter Quellcode aller Klassen)
4.3 Erläutern sie, in welchen Teilen des Modells Anpassungen vorgenommen werden müssen,
um von einer Infix-Notation auf eine Prefix-Notation zu wechseln! Welche Anpassungen müssten am Modell durchgeführt werden, wenn man von Anfang an das Visitor-Muster verwendet
hätte? Welche Vorteile bringt das Visitor-Muster? Hat das Visitor-Muster auch Nachteile?
(Abgabe: Erklärung)
4.4 Erweitern Sie das ursprüngliche Klassendiagramm aus Teilaufgabe 4.1 um die Klassen,
die für das Visitor-Muster benötigt werden und generieren sie wieder den Code! Implementieren sie mittels des Visitor-Musters die textuelle Darstellung von Formeln in Prefix-Notation
und geben sie die beiden Formeln aus Aufgabe 4.1 aus! (Abgabe: Screenshot des Klassendiagramms, kommentierter Quellcode aller Klassen)
4
Herunterladen