Software Engineering 11. Entwurfsmuster III

Werbung
Software Engineering
11. Entwurfsmuster III
Franz-Josef Elmer, Universität Basel, HS 2012
Software Engineering: 11. Entwurfsmuster III
2
Entwurfsmuster: Composite
–
Compose objects into a tree structures to represent part-whole
hierarchies. Composite lets clients treat individual objects and
compositions of objects uniformly.
GoF(163)
–
Struktur:
Client
«Interface»
Component
operation()
add(c:Component)
remove(c:Component)
getChild(index:int)
children
*
0..1 parent
Leaf
+operation()
Universität Basel, HS 2012
Composite
operation()
add(c:Component)
remove(c:Component)
getChild(index:int)
for each child do
child.operation();
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
3
Composite
–
Beteiligte Klassen:
●
●
●
●
–
Component:
– Definiert ein Interface für alle Objekte des Baumes
Leaf:
– Repräsentiert ein Blatt im Baum
Composite:
– Definiert das Verhalten eines Knoten mit Kindern
– Hält die Kindkomponenten
– Implementiert alle Operation, die sich auf Kinder beziehen
Client:
– Manipuliert Objekte im Baum via dem Component Interface
Zusammenarbeit:
●
Der Client ruft für ein beliebiges Objekt im Baum operation() auf.
Abhängig von der Objektklasse bewirkt operation() unterschiedliches.
Im Fall eines Composite Objekts wird der Aufruf an alle Kinder
weitergereicht. Eventuell werden davor und/oder danach noch
zusätzliche Operationen ausgeführt.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
4
Composite
–
Anwendbar wenn
●
–
eine baumartige Struktur aus Objekten modelliert werden soll und der
Unterschied zwischen Leaf und Composite in gewissen Kontexten
ignoriert werden kann.
Konsequenzen:
●
●
Definiert eine Klassenhierarchie aus einfachen Objekten und
zusammengesetzten Objekten.
Vereinfacht den Client, da einfache und zusammengesetzte Objekt
gleich behandelt werden.
–
●
●
Ausnahme: Manipulationen der Baumstruktur
Es ist einfach neue Objekttypen hinzuzufügen (Open-Closed Prinzip).
Nachteil: Manchmal zu Allgemein. Dies kann zu Typenüberprüfung zur
Laufzeit führen.
–
Universität Basel, HS 2012
Beispiel: Eine neuer Typ hat eine spezielle Methode, die nicht im Component
Interface deklariert ist.
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
5
Composite
–
Implementierung:
●
Kindkomponente hat expliziten Zugriff auf Elternkomponente:
«Interface»
Component
+getParent():Composite
...
Component
-parent:Composite
+getParent():Composite
+setParent(p:Composite)
...
In den Implementierungen der Methoden add() und remove() von Composite muss dies
entsprechend berücksichtigt werden.
●
Die Kinder eines Composite-Objekts müssen nicht geordnet sein.
–
●
oder
Konsequenz: Anderes Zugriffsinterface, z.B. getChildren():Component[*] statt
getChild(index:int)
Maximierung des Component Interfaces durch Hinzufügen von so
vielen gemeinsamen Operationen wie möglich.
–
–
Universität Basel, HS 2012
Vorteil: Client muss nicht den Typ der Komponente prüfen
Nachteile: Operation machen für gewisse Typen keinen Sinn.
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
6
Composite: Implementierung
–
Deklaration der Methoden des Kinder Managements:
●
im Component Interface:
–
–
●
Vorteil: Einheitliches Interface aller Knoten im Baum
Nachteile:
●
Überprüfung des Knotentyps für Operationen wie Hinzufügen oder Wegnehmen
eines Kindes.
●
Fragwürdige Implementierungen dieser Operationen in den Leaf Klassen.
in der Composite Klasse:
–
–
Vorteil: Kinder Management nur dort
wo es Sinn macht.
Nachteil: Client Klasse muss bei
Manipulationen des Baums auf
Composite überprüfen und
umwandeln.
TreeUser
«Interface»
Component
operation()
children
*
0..1
Composite
TreeBuilder
Universität Basel, HS 2012
operation()
add(c:Component)
remove(c:Component)
getChild(index:int)
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
7
Composite: Beispiele
–
Java AWT Components:
Component
paint(g:Graphics)
getParent():Container
*
0..1
Container
add(c:Component)
remove(c:Component)
getComponentCount():int
getComponent(index:int)
–
W3C XML DOM API:
«Interface»
Node
appendChild(c:Node):Node
* getChildNodes():NodeList
0..1
«Interface»
Element
setAttributeNode(a:Attr):Attr
getAttributeNode(name:String):Attr
Universität Basel, HS 2012
0..1
if leaf
throw
DOMException
«Interface»
Attr
* getName():Name
getValue():String
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
8
Entwurfsmuster: Iterator
–
Provide a way to access the elements of an aggregate object
sequentially without exposing its underlying representation.
GoF(257)
–
Struktur:
«Interface»
Aggregate
createIterator():Iterator
Client
«Interface»
Iterator
first():Object
next():Object
current():Object
isDone():boolean
ConcreteAggregate
createIterator():Iterator
ConcreteIterator
1
return new ConcreteIterator(this);
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
9
Iterator
–
Beteiligte Klassen:
●
●
●
●
–
Iterator:
– Definiert ein Interface für den sequentiellen Zugriff auf die Objekte
einer Ansammlung von Objekten (engl.: aggregate, collection).
ConcreteIterator:
– Implementiert das Iterator Interface und hält die momentane
Position des Zugriffs (durch current() abfragbar).
Aggregator:
– Definiert ein Interface zur Erzeugung eines Iterator Objekts.
ConcreteAggregator:
– Implementiert das Aggregator Interface und erzeugt eine Instanz
einer passenden ConcreteIterator Klasse.
Zusammenarbeit:
●
●
●
Mit first() holte der Client das erste Objekt.
Mit next() wird das jeweils darauf folgende Objekt geholt.
Mittels isDone() kann der Client feststellen, ob es noch weiter Objekte
gibt oder nicht.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
10
Iterator
–
Anwendbar wenn
●
●
–
auf die Objekte einer Ansammlung zugegriffen werden soll, ohne
interne Repräsentation der Ansammlung preiszugeben
ein einheitliches Interface zum Zugriff unterschiedlicher Typen von
Ansammlungen benötigt wird.
Konsequenzen:
●
●
Konform mit dem Geheimnisprinzip.
Unterschiedliche Iterator-Implementierungen erlauben eine
Aggregatstruktur auf unterschiedliche Weise zu durchlaufen.
–
●
●
●
●
Beispiel: Baumstruktur kann entweder zuerst in die Tiefe (deep first) oder in Breite
(breadth first) durchlaufen werden.
Iterator vereinfacht das Aggregate Interface (nur eine Methode).
Mehrere Iteratoren können parallel die Ansammlung durchlaufen.
Die Operation zur Erzeugung eines Iterator ist eine Factory Methode.
Problem: Was passiert wenn die Aggregatstruktur sich während der
Iteration ändert?
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
11
Iterator
–
Implementierung:
●
●
●
Statt der vier Operationen des Iterators (first, next, current, isDone) sind
auch weniger möglich. Im einfachsten Fall gibt es nur eine Operation
next() welche das nächste Objekt oder ein Null-Objekt liefert.
Der Traversierungs Algorithmus ist entweder in der konkreten Iterator
Klasse implementiert oder in der konkreten Aggregat Klasse. Im letztern
Fall speichert der Iterator nur die momentane Position. Ein solcher
Iterator wird auch Cursor genannt.
In Java sind konkrete Iteratoren oft private innere Klassen der konkreten
Aggregatoren.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
12
Iterator: Beispiele aus der Java API
–
Interface Enumeration:
«Interface»
Enumeration
nextElement():Object
hasMoreElements():boolean
–
Collection API:
●
Aggregator ≙ Collection
«Interface»
Collection
iterator():Iterator
...
–
Java Database Connection (JDBC) API:
●
●
«Interface»
Iterator
next():Object
hasNext():boolean
remove()
Aggregator ≙ Statement
Iterator ≙ ResultSet
«Interface»
Statement
executeQuery(sql:String):ResultSet
...
Universität Basel, HS 2012
«Interface»
ResultSet
next():boolean
getObject(index:int):Object
...
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
13
Entwurfsmuster: Proxy
–
Provide a surrogate or placeholder for another object to control
access to it.
GoF(207)
–
Struktur:
Client
«Interface»
Subject
operation()
Proxy
operation()
-realSubject
RealSubject
1 operation()
...
realSubject.operation()
...
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
14
Proxy
–
Beteiligte Klassen:
●
●
●
–
Subject:
– Gemeinsames Interface von RealSubject und Proxy.
RealSubject:
– Definiert reales Objekt welches durch das Proxy Objekt
repräsentiert wird.
Proxy:
– Ersatz für das reale Objekt.
– Delegiert den Methodenaufruf an das reale Objekt weiter.
– Kontrolliert den Zugriff auf ein reales Objekt.
Zusammenarbeit:
●
●
Aufrufe der im Subject Interface definierten Methoden werden über das
Proxy Objekt an das reale Objekt weitergeleitet.
Das Proxy Objekt kann davor und/oder danach weitere Aktionen
ausführen.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
15
Proxy
–
Anwendbar wenn
●
●
●
●
–
das reale Objekt zu Beginn noch nicht zur Verfügung steht
das reale Objekt zur Laufzeit gewechselt werden soll, ohne dass der
Client etwas davon mitbekommt
das reale Objekt vor unberechtigtem Zugriff geschützt werden soll
ganz allgemein vor und/oder nach dem Aufruf weitere Operationen
nötig sind (z.B. Logging) → Aspect Oriented Programming (AOP)
Konsequenzen:
●
●
Konform mit dem Geheimnisprinzip.
Proxy Typen:
–
–
–
●
Remote Proxy: Proxy für ein Remote Objekt
Virtual Proxy: Proxy als Cache des realen Objekts
Protection Proxy: Proxy überprüft Zugriffsberechtigung
Copy-on-Write: Statt ein reales Objekt zu kopieren (was viel Zeit
und/oder Speicher kosten kann) wird zunächst nur ein Proxy davon
erzeugt. Erst wenn die „Kopie“ verändert werden soll, wird das reale
Objekt wirklich kopiert.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
16
Proxy
–
Implementierung:
●
Die Proxy Klasse muss nicht immer die RealSubject Klasse kennen:
1
«Interface»
Subject
operation()
Proxy
operation()
–
●
RealSubject
operation()
Ausnahme: Virtual Proxy muss eine Instanz von RealSubject erzeugt. wenn es das
erste mal gebraucht wird (lazy initialization).
Java Dynamic Proxy (java.lang.reflect.Proxy): Erlaubt zur Laufzeit die
Erzeugung eines Proxys für ein beliebiges Objekt. Beschränkung:
Dieser dynamische Proxy funktioniert nur für Methoden die in einem
Interface deklariert sind.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
17
Entwurfsmuster: Command
–
Encapsulate a request as an object, thereby letting you
parameterize clients with different requests and support undoable
operations.
GoF(233)
–
Struktur:
Invoker
setCommand(c:Command)
Receiver
action()
-receiver
1
«Interface»
1 Command
execute()
ConcreteCommand
excute()
Client
receiver.action()
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
18
Command
–
Beteiligte Klassen:
●
●
●
●
●
–
Command:
– Definiert ein Interface für die Ausführung einer Operation.
ConcreteCommand:
– Implementiert execute() durch Aufruf einer korrespondierenden Aktion
im gebundenen Receiver Objekt.
Receiver:
– Führt die eigentliche Operation aus.
Invoker:
– Initiiert die Ausführung der Operation via Command Interface.
Client:
– Bindet einen Invoker an einen Receiver via einer ConcreteCommand
Instanz.
Zusammenarbeit:
●
●
Client erzeugt ConcreteCommand Objekt zu einem spezifischen
Receiver Objekt und übergibt es der Invoker Instanz.
Der Invoker ruft die execute() Operation seiner Command Instanz auf,
welche den Aufruf an den Receiver weiterleitet.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
19
Command: Zusammenarbeit
:Client
:Invoker
«create»
:Receiver
c:ConcreteCommand
setCommand()
execute()
action()
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
20
Command
–
Anwendbar wenn
●
●
●
parametrisierbare Aktion benötigt wird
die Spezifizierung und Ausführung einer Aktion zu unterschiedlichen
Zeiten erfolgen soll
ein Undo Mechanismus benötigt wird
–
–
Command Interface muss um eine undo() Methode erweitert werden und
ConcreteCommand muss den alten Zustand speichern.
Konsequenzen:
●
●
Entkopplung zwischen dem Objekt, welches eine Operation einleiten
will, und dem Objekt, welches weiss wie die Operation ausgeführt wird.
Konform mit den Designprinzipien
–
–
●
Geheimnisprinzip
Open-Closed Prinzip
Unter Einbezug des Composite Patterns können zusammen-gesetzte
Kommandos aus einfachen aufgebaut werden.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
21
Entwurfsmuster: Adapter
–
Convert the interface of a class into another interface clients
expect. Adapter lets classes work together that couldn't otherwise
because of incompatible interfaces.
GoF(139)
–
–
Alternativer Name: Wrapper
Struktur:
Client
«Interface»
Target
request()
Adapter
request()
-adaptee
Adaptee
1 specificRequest()
adaptee.specificRequest()
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
22
Adapter
–
Beteiligte Klassen:
●
●
●
●
–
Target:
– Definiert ein domänenspezifisches Interface welches der Client
braucht.
Adaptee:
– Definiert ein existierendes Interface oder Klasse, die inkompatible
zum Target Interface ist.
Adapter:
– Klasse, die das Target Interface implementiert und alle TargetAufrufe in Adaptee-Aufrufe umsetzt.
Client:
– Klasse, die mit Target aber nicht mit Adaptee zusammen-arbeiten
kann.
Zusammenarbeit:
●
●
Adapter vermittelt zwischen dem Client (der nur das Target Interface
versteht) und dem Adaptee.
Jeder Aufruf einer Target Methode wird vom Adapter in Adaptee
Operationen umgewandelt.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
23
Adapter
–
Anwendbar wenn
●
●
–
eine Klasse wiederverwendet werden soll, deren Interface aber nicht
passt
Client und Target Klassen eines Frameworks sind
Konsequenzen:
●
●
●
Der Umfang eines Adapters hängt von der Ähnlichkeit zwischen Target
Interface und Interface der wiederverwendeten Klasse (Adaptee) ab.
Konform mit den Geheimnisprinzip
Framework Design: Target Interfaces sollten minimalistisch entworfen
werden, d.h so wenig Operationen wie möglich mit so wenig
Vorraussetzungen wie möglich. Dies erleichert das Schreiben von
Adapterklassen.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
24
Adapter: Ein kleines Beispiel
–
FileBrowser: Baumansicht des Filesystems mit Java Swing
●
●
●
Client ≙ JTree
Target ≙ TreeModel
Adaptee ≙ File
«Interface»
TreeModel
getRoot():Object
getChildCount(parent:Object):int
isLeaf(node:Object):boolean
getChild(parent:Object,index:int):Object
getIndexOfChild(parent:Object,child:Object):int
...
File
getName():String
getLength():long
lastModified():long
isDirectory():boolean
listFiles():File[]
getParentFile():File
...
1
FileTreeModel
-rootNode
FileNode
1 getFile():File
toString():String
●
FileNode (auch ein Adapter) wird gebraucht, weil der Standard
TreeCellRenderer einen Baumknoten mittels toString() als Text
darstellt.
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
25
Adapter: FileTreeModel
public class FileTreeModel implements TreeModel
{
private final FileNode _rootNode;
public FileTreeModel(File dir) {
_rootNode = new FileNode(dir);
}
public Object getRoot() {
return _rootNode;
}
public int getChildCount(Object parent) {
File file = ((FileNode) parent).getFile();
return file.isDirectory() ? file.listFiles().length : 0;
}
public boolean isLeaf(Object node) {
return ((FileNode) node).getFile().isDirectory() == false;
}
public Object getChild(Object parent, int index) {
File file = ((FileNode) parent).getFile();
return file.isDirectory() ? new FileNode(file.listFiles()[index]) : null;
}
public int getIndexOfChild(Object parent, Object child) {
File dir = ((FileNode) parent).getFile();
File file = ((FileNode) child).getFile();
return dir.isDirectory() ? Arrays.asList(dir.listFiles()).indexOf(file) : -1;
}
}
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Software Engineering: 11. Entwurfsmuster III
26
Adapter: FileNode und FileBrowser
class FileNode {
private static final NumberFormat FORMATTER = new DecimalFormat("#,##0");
private final File _file;
public FileNode(File file) {
_file = file;
}
public File getFile() {
return _file;
}
public String toString() {
String name = _file.getName();
if (_file.isDirectory() == false) {
name += " [" + FORMATTER.format(_file.length()) + " bytes]";
}
return name;
}
public class FileBrowser {
}
public static void main(String[] args) {
File userHomeDir = new File(System.getProperty("user.home"));
JTree tree = new JTree(new FileTreeModel(userHomeDir));
JFrame frame = new JFrame("FileBrowser");
frame.getContentPane().add(new JScrollPane(tree));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 500);
frame.show();
}
}
Universität Basel, HS 2012
© Franz-Josef Elmer 2012
Herunterladen