1 Entwurfsmuster
Beantworten Sie kurz und bündig folgende Fragen!
-
Welche Vorteile ergeben sich durch den Einsatz eines Entwurfsmusters?
- Wiederverwendung von erprobten Lösungen
- Verbesserte Qualität (Verständlichkeit, Wartbarkeit)
- Kostenersparnis durch effizienteren Entwicklungsprozess
-
Entwurfsmuster werden in drei Kategorien unterteilt. Nennen Sie die Kategorien sowie jeweils ein passendes Entwurfsmuster:
- Creational: Singleton – stellt sicher, dass eine Klasse nur ein Exemplar hat und bietet einen globalen Zugriffspunkt darauf.
- Structural: Adapter – ermöglicht das Zusammenarbeiten von Klassen mit inkompatiblen Schnittstellen, indem es die Schnittstelle einer Klasse in eine andere Schnittstelle übersetzt.
- Behavioural: Observer – definiert eine Abhängigkeit zwischen Objekten, sodass, wenn ein Objekt seinen Zustand ändert, alle abhängigen Objekte darüber benachrichtigt und automatisch aktualisiert werden.
-
Manche Entwurfsmuster werden oftmals miteinander kombiniert und arbeiten zusammen. Geben Sie hierfür zwei Beispiele an und erklären diese kurz:
- Behavioural + Structural: Visitor + Composite – Ermöglicht verschiedene Operationen auf einer Objektstruktur durchzuführen, ohne die Objekte selbst zu ändern. Besonders nützlich, wenn viele Objekttypen vorhanden sind und je nach Typ unterschiedliche Aktionen ausgeführt werden sollen.
- Behavioural: Iterator + Composite – Vereinfacht den Zugriff und die Durchquerung von komplexen Strukturen. Der Iterator ermöglicht es, alle Elemente einer Struktur wie durch eine einfache Liste zu durchlaufen, was besonders bei zusammengesetzten Strukturen wie Bäumen hilfreich ist.
2 Entwurf von Klassenhierarchien
Wir betrachten in dieser Aufgabe Terme über die Rechenarten , die rekursiv definiert sind:
-
Definition:
- Jedes Literal ist ein Term, z.B. „4“.
- Ist ein Term, so ist „()“ ein (geklammerter) Term.
- Sind , Terme, so ist „“ ebenso ein Term.
-
Beispiele für gültige Terme:
- , , oder .
Aufgaben:
a) Modellieren Sie eine Klassenstruktur in UML
Mit Hilfe dieser Struktur soll eine rekursive Struktur von Termen erstellt werden. Sehen Sie mindestens einzelne Klassen für die Addition und Multiplikation vor sowie weitere Klassen für geklammerte Terme und Literale, die ganze Zahlen repräsentieren.
Erkl
Composite Pattern:
Das Composite Pattern ist ein strukturelles Entwurfsmuster, das es ermöglicht, Objekte in Baumstrukturen zu organisieren, um Teil-Ganzes-Hierarchien darzustellen. Es erlaubt Clients, einzelne Objekte und Kompositionen von Objekten einheitlich zu behandeln. In diesem Kontext ermöglicht es die Behandlung von einfachen Termen (Literals) und komplexen Termen (wie Addition und Multiplikation) auf die gleiche Weise.Beispiel:
Ein Ausdruck wie4 + (5 * 6)
kann als Baum dargestellt werden, bei dem die Wurzel die Addition ist und die Kinder die Literale4
und das Ergebnis der Multiplikation5 * 6
.
b) Zeichnen Sie das UML-Klassendiagramm.
classDiagram
Term <|-- Literal
Term <|-- BinaryOperator
BinaryOperator <|-- Addition
BinaryOperator <|-- Multiplication
Term <|-- Brackets
class Term {
<<abstract>>
+ accept(visitor: Visitor)
}
class Literal {
- value : int
+ accept(visitor: Visitor)
}
class BinaryOperator {
<<abstract>>
- left : Term
- right : Term
+ accept(visitor: Visitor)
}
class Addition {
+ accept(visitor: Visitor)
}
class Multiplication {
+ accept(visitor: Visitor)
}
class Brackets {
- inner : Term
+ accept(visitor: Visitor)
}
Erkl
Klassendiagramm Erklärung:
- Term: Die abstrakte Basisklasse für alle Termtypen. Sie deklariert die Methode
accept
, die für das Visitor-Pattern erforderlich ist.- Literal: Repräsentiert numerische Werte. Enthält einen ganzzahligen Wert und implementiert die
accept
Methode.- BinaryOperator: Eine abstrakte Klasse für binäre Operationen wie Addition und Multiplikation. Sie hält Referenzen auf die linken und rechten Terme.
- Addition & Multiplication: Konkrete Klassen, die von
BinaryOperator
erben und dieaccept
Methode implementieren.- Brackets: Repräsentiert geklammerte Ausdrücke und hält einen inneren Term.
U Decorator
Modellieren Sie folgenden Sachverhalt als UML-Klassendiagramm. Gehen Sie dabei davon aus, dass für die Implementierung Java zu benutzen wäre. Sie müssen jedoch keine Implementierung erstellen, sondern nur das UML-Klassendiagramm. Sie werden feststellen, dass ein naiver Ansatz problematisch ist. Besser ist es, auf ein passendes Entwurfsmuster zurückzugreifen. Welches Entwurfsmuster wäre hierfür geeignet?
Eine Grafikbibliothek soll die Verwendung folgender Fenstertypen erlauben:
- einfache Fenster ohne Zusatzfunktionalität
- Fenster, die eine Titelleiste haben
- Fenster, die eine Statusleiste haben
- Fenster, die horizontal und vertikal „scrollbar“ sind
- alle daraus konstruierbaren „Featurekombinationen“, wie z. B. ein Fenster mit Titelleiste das horizontal und vertikal „scrollbar“ ist
Empfohlenes Entwurfsmuster:
Decorator Pattern
Erkl
Decorator Pattern:
Das Decorator Pattern ist ein strukturelles Muster, das es ermöglicht, einem Objekt zur Laufzeit zusätzliche Funktionalitäten hinzuzufügen, ohne die Klassenhierarchie zu verändern. Es wird erreicht, indem das zu dekorierende Objekt in ein Dekorator-Objekt eingewickelt wird, das die zusätzliche Funktionalität bereitstellt.Beispiel:
Ein einfaches Fenster (Window
) kann mit einer Titelleiste (TitleBarDecorator
) und/oder einer Statusleiste (StatusBarDecorator
) dekoriert werden. Dadurch entsteht ein Fenster mit kombinierten Funktionen, ohne für jede Kombination eine eigene Klasse zu erstellen.
Das Decorator Pattern verhindert die exponentielle Explosion von Klassen, die bei einem naiven Ansatz entstehen würde, indem es die Flexibilität bietet, Features dynamisch zu kombinieren.
U Visitor Pattern
In dieser Aufgabe sollen Sie das Visitor-Pattern anwenden. Wir möchten dabei einen Visitor für die Klassenstruktur aus Aufgabe 2 implementieren.
Es soll möglich sein, Terme auf der Konsole auszugeben oder deren Wert zu berechnen.
a) Erweiterung des Klassendiagramms aus Aufgabe 2 um die Klasse Visitor
classDiagram
Term <|-- Literal
Term <|-- BinaryOperator
BinaryOperator <|-- Addition
BinaryOperator <|-- Multiplication
Term <|-- Brackets
Term <|.. Visitor
class Term {
<<abstract>>
+ accept(visitor: Visitor)
}
class Literal {
- value : int
+ accept(visitor: Visitor)
}
class BinaryOperator {
<<abstract>>
- left : Term
- right : Term
+ accept(visitor: Visitor)
}
class Addition {
+ accept(visitor: Visitor)
}
class Multiplication {
+ accept(visitor: Visitor)
}
class Brackets {
- inner : Term
+ accept(visitor: Visitor)
}
class Visitor {
<<interface>>
+ visitLiteral(literal: Literal)
+ visitAddition(addition: Addition)
+ visitMultiplication(multiplication: Multiplication)
+ visitBrackets(brackets: Brackets)
}
Erkl
Visitor Pattern:
Das Visitor Pattern ist ein Verhaltensmuster, das es ermöglicht, neue Operationen auf einer Objektstruktur durchzuführen, ohne die Klassen dieser Struktur zu ändern. Es trennt die Algorithmen von den Objektstrukturen, wodurch die Erweiterbarkeit verbessert wird.Anwendung im Beispiel:
In diesem Fall ermöglicht derVisitor
verschiedene Operationen wie das Ausgeben des Terms oder das Berechnen seines Wertes, ohne die Termklassen selbst zu verändern. Jede Termklasse implementiert dieaccept
Methode, die den entsprechendenVisitor
akzeptiert und dessen Besuchsmethode aufruft.
b) Implementierung
Fertigen Sie eine Implementierung für diese Klassenstruktur an, welche die oben genannten Terme anlegt und über die Visitor-Klassen ausgibt bzw. den Wert berechnet.
Erkl
Implementierungserklärung:
- Visitor Interface: Definiert die Besuchsmethoden für jede konkrete Termklasse.
- PrintVisitor: Implementiert den
Visitor
zur Ausgabe des Ausdrucks auf der Konsole. Es traversiert den Ausdrucksbaum und gibt die Struktur mit Klammern und Operatoren aus.- EvalVisitor: Implementiert den
Visitor
zur Berechnung des Ausdruckswerts. Es traversiert den Baum und berechnet rekursiv die Werte der Terme.- Main Klasse: Erstellt einen Ausdruck (
4 + (5 * 6)
), verwendet denPrintVisitor
zur Ausgabe und denEvalVisitor
zur Berechnung des Wertes.
Ausgabe:
(4 + (5 * 6))
Wert: 34
Beispiel
Ausdrucksstruktur:
Der Ausdruck4 + (5 * 6)
wird als Baum dargestellt:
- Addition
- Literal: 4
- Brackets
- Multiplication
- Literal: 5
- Literal: 6
Traversierung durch Visitor:
- PrintVisitor: Gibt die Struktur mit Klammern und Operatoren aus.
- EvalVisitor: Berechnet zuerst
5 * 6 = 30
und dann4 + 30 = 34
.
K Entwurfsmuster
a) Beobachter Entwurfsmuster (Observer-Pattern)
Stellen Sie das Beobachter Entwurfsmuster (Observer-Pattern) in einem UML-Klassendiagramm dar (inkl. wichtige Methoden aber ohne deren Inhalt sowie ohne Multiplizitäten und Rollennamen). Abstrakte Klassen können Sie ggf. mit [abstract]
unter dem Klassennamen markieren. Damit Sie Ihre Lösung besser einschätzen können, bekommen Sie für diese Aufgabe eine Bewertung in Punkten. Die maximale Punktzahl ist 8. Diese Punkte dienen lediglich der Einschätzung Ihrer Lösung und sind keine Bonuspunkte.
classDiagram
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
Subject <|-- Observer
ConcreteObserver <|-- ConcreteSubject
class Subject {
<<interface>>
+ attach(observer: Observer)
+ detach(observer: Observer)
+ notify()
}
class ConcreteSubject {
- state : String
+ attach(observer: Observer)
+ detach(observer: Observer)
+ notify()
+ getState() : String
+ setState(state: String)
}
class Observer {
<<interface>>
+ update(subject: Subject)
}
class ConcreteObserver {
- observerState : String
+ update(subject: Subject)
}
Erkl
Observer Pattern:
Das Observer Pattern ist ein Verhaltensmuster, das eine Eins-zu-viele-Abhängigkeit zwischen Objekten definiert. Ein Objekt (Subject) benachrichtigt automatisch alle abhängigen Objekte (Observers), wenn sich sein Zustand ändert.Komponenten des Musters:
- Subject (Interface): Definiert Methoden zum Anhängen, Abziehen und Benachrichtigen von Beobachtern.
- ConcreteSubject: Implementiert das
Subject
Interface und hält den Zustand, den die Beobachter beobachten.- Observer (Interface): Definiert die
update
Methode, die vom Subject aufgerufen wird.- ConcreteObserver: Implementiert das
Observer
Interface und hält den eigenen Zustand, der durch Benachrichtigungen aktualisiert wird.
Example
Praktische Anwendung:
Ein Newsletter-System, bei dem derConcreteSubject
der Newsletter ist. MehrereConcreteObserver
sind Abonnenten, die informiert werden, wenn ein neuer Newsletter veröffentlicht wird.Ablauf:
- Ein
ConcreteObserver
abonniert denConcreteSubject
mittelsattach
.- Wenn sich der Zustand des
ConcreteSubject
ändert (z.B. ein neuer Newsletter erscheint), ruft das Subjectnotify
auf.- Das Subject iteriert über alle abonnierten Beobachter und ruft deren
update
Methode auf.- Jeder
ConcreteObserver
aktualisiert seinen Zustand entsprechend der neuen Informationen vom Subject.
Dieses Muster fördert lose Kopplung zwischen Subjekt und Beobachtern, wodurch die Wartbarkeit und Erweiterbarkeit des Systems verbessert wird.