Strukturmuster: Kompositum
... [ Seminar Objektorientierter Entwurf] ... [ Thema Entwurfsmuster ] ...
[ Literaturverzeichnis ] ...
bersicht: Strukturmuster: Kompositum
Kompositum
( Composite )
Ist ein objektbasiertes Strukturmuster.
Zweck
Es gibt den Klienten die Möglichkeit einzelne Objekte und Kompositionen von
Objekten einheitlich zu behandeln. Die Objekte werden zu Baumstrukturen
zusammengefügt.
Motivation
Stellen Sie sich vor, Sie brauchen ein Grafiksystem. In diesem System wollen
Sie aus Linien, Rechtecken, und Text größere Abbildungen darstellen.
Diese Abbildungen sollen auch wieder andere Abbildungen rekursive enthalten
können.
Sie brauchen also primitive Objekte die Linie, das Rechteck und den Text.
Zusätzlich brauchen Sie Behälter, die weitere Behälter und
primitive Objekte enthalten können.
Diese Struktur bilden wir mit dem Kompostum-Muster ab.
Wir nehmen eine abstrakte Klasse Grafik mit den abstrakten Methoden Zeichen,
FuegeHinzu, Entferne und GibKindObjekt. Von dieser Klasse leiten wir durch
Vererbung die primitiven Klassen Linie, Rechteck und Text ab. Wir
überschreiben nur die Methode Zeichne, die das Objekt selbst zeichnet.
Als Behälter leiten wir die Klasse Abbildung von Grafik ab. In Abbildung
setzen wir alle Methoden um. Wir halten zusätzlich eine mehrfachige
Aggregation auf die Klasse Grafik um alle Objekte (primitive und Abbildungen)
zu erfassen. Über diese Menge oder Liste von Grafikobjekten wird bei der
Methode Zeichne jedes Objekt mit Zeichne aufgerufen. Die Methoden FuegeHinzu,
Entferne und GibKindObjekte werden zur Verwaltung der Grafikobjekte benutzt.
Anwendbarkeit
Das Kompositionsmuster ist Anwendbar, wenn
- Sie Teil-Ganzes-Hierarchien von Objekten repräsentieren wollen.
- Sie wollen, daß die Klienten alle Objekte einheitlich behandeln
sollen. Die Klienten sollen nicht zwischen einzelnen und zusammengesetzten
Objekten unterscheiden können.
Struktur
Teilnehmer
- Komponente
- sie deklariert die Schnittstelle für alle Objekte.
- Wenn es angebracht ist, wird Defaultverhalten implementiert.
- Blatt
- Besitzt keine Kindobjekt und repräsentiert die Blattobjekte.
- Definiert das Verhalten von primitiven Objekten in der Konposition.
- Kompositum
- Speichert und verwaltet die Kindobjekte.
- Implementiert und definiert das Verhalten mit den Kindobjektbezogenen Operationen.
- Klient
- Manipulliert die Objekte in der Komposition durch die Schnittstelle von der
Komponente.
Interaktion
Die Klienten führen interaktionen über die Klassenschnittstelle der
Komponente aus. Ist ein Blatt der Empfänger, wird die Aktion direkt
ausgeführt. Ist jedoch ein Kompositum der Empfänger, werden die
Kindobjekte mit der gleichen Anfrage aufgerufen. Vor oder nach dem Aufruf
können noch zusätzliche Aktionen ausgeführt werden;
Konsequenzen
- Der Klient kann vereinfacht auf Blattobjekte und Kompositionsstrukturen
zugreifen, denn alle Objekte werden gleich behandelt. Den Klienten sollte
es egal sein, ob sie es gerade mit einem Blatt oder einer zusammengesetzten
Komponente zu tun haben.
- Es einfach für Sie neue Arten von Komponenten hinzuzufügen.
Die neuen Blatt- und Kompositionsklassen benutzen die gleiche
Schnittstelle, deshalb muß der Klientencode nicht geändert
werden.
- Der Nachteil ist die Möglichkeit viele Blatt- und Kompositionsklassen
zu definieren. Dadurch kann der Entwurf zu allgemein und
unübersichtlich werden. Wenn dann noch eine Komposition nur aus
bestimmten Komponenten bestehen soll, ist diese ein Einschränkung
nicht ohne Mehraufwand zur Laufzeit zu bewältigen.
Implementierung
Bei der Implementierung des Kompositionsmusters sollten Sie folgenden Punkte
bedenken:
- Explizite Referenz auf das Elternobjekt
Eine Referenz auf das Elternobjekt kann den Verwaltungsaufwand verkleinern.
Zusätzlich wird das Implementieren von weiteren Entwurfmustern erleichtert,
wie zum Beispeil das Zuständigkeitsketten-Muster.
- Gemeinsame Nutzung von Komponenten
Dadurch können die Speicheranforderungen an das System gesenkt werden.
Das Fliegengewichtmuster beschreibt eine Umsetzungsmöglichkeit.
- Maximieren der Komponentenschnittstelle
Die Komponentenklasse sollte so viele gemeinsame Operationen der Blatt- und
Kompositionsklassen definieren wie möglich (nötig).
- Deklarieren von Verwaltungsoperationen für Kindobjekte
Die Operationen zur Verwaltung von Kindobjekten werden nur in den Kompositionsklassen
benötigt. Es gibt zwei Möglichkeiten diese Operationen zu
implementieren :
- Die Operationen werden in der Wurzel der Klassenhierarchie definiert. Dadurch
erreichen Sie Transparenz in ihrer Klassenhierarchie. Aber die Klienten
können sinnlos versuchen in einem Blattobjekt eine Verwaltungtsoperation
aufzurufen, dafür sollte in der Wurzelklasse ein Defaultverhalten
implementiert werden. Dieses Defaultverhalten wird von den Blattklassen benutzt
und von den Kompositionsklassen überschrieben. Nun haben Sie Transparenz
und können jedes Objekt der Klassenhierarchie mit jeder Operation aufrufen.
Nur führt dieses manchmal dazu, daß eine Fehlermeldung (Exception)
ausgelöst wird oder es daß gar nichts passiert.
- Die Verwaltungsoperationen werden nur in den Kompositionsklassen definiert.
Dadurch haben Sie Sicherheit, daß es gar nicht möglich ist ein
Blattobjekt mit einer Verwaltungsoperation aufzurufen. Diese Aufrufe werden zur
Überstzungszeit abgefangen. Sie haben jedoch nun an Tranzparenz verloren,
weil nun Blätter und Kompsita unterschiedliche Schnittstellen besitzen.
- Ort des Behälters für enthaltene Komponenten
Der Behälter für die Kindobjekte wird lediglich in den Kompositionsklassen
gebraucht. Werden nun die Behälter in der Komponentenklassen implementiert,
führt dies zu einer Speicherplatzverschwendung in den Blättern.
- Ordnung der Kindobjekte
Manchmal müssen sich die Kindobjekte eines Kompositums in einer bestimmten
Ordnung oder Reihenfolge befinden, z.B. wenn die Komposita Parsebäume
repräsentieren. Hierbei ist es wichtig, daß die Zugriffs- und
Verwaltungsoperationen die Reihenfolge der Kondobjekte korrekt verwalten.
Hilfreich kann dazu das Iteratormuster sein.
- Löschen der Komponente
Machen Sie am besten das jeweilige Kompositum für das Löschen seiner
Kindobjekte verantwortlich. Wird das Kompositum gelöscht, muß das
Kompositum seine Kindobjekte löschen. Das gilt natürlich nur für
Sprachen ohne automatischer Speicherbereinigung (Garbage Collection).
- Datenstrukturen zum Speichern von Komponenten
Zum Speichern von Kindobjekten können Komposita eine Vielzahl von
Datenstrukturen verwenden, das hängt von der gewünschten Effizienz ab.
(z.B. verkettete Listen, Bäume, Arrays, Hash-Tabellen,...).
Beispielcode
Die abstrakte Klasse Grafik als Kompositum-Wurzel:
public abstract class Grafik{
public abstract void Zeichne();
}
Die Klassen Linie, Rechteck und Text als Blattklassen:
public class Linie extends Grafik{
Point p1, p2;
public void Zeichne(){...}
}
public class Rechteck extends Grafik{
point Linksoben, rechtsunten;
public void Zeichne(){...}
}
public class Text extends Grafik{
point p;
String text;
public void Zeichne(){...}
}
Die Klasse Abbildung als Kompositum:
public class Abbildung extends Grafik{
Liste liste // eine eigene Listen-Klasse
public void Zeichen() {
for(i = liste.start(); i < liste.Count(); i++)
liste[i].Zeichne()
}
public void FuegeHinzu(Grafik g) { liste.add(g) }
public void Entferne(Grafik g) {...}
public void GibKindObjekt(int i) {...}
}
Bekannte Verwendungen
- Smalltalk MVC-Triade (Modell-View-Controller). Die View-Klassen benutzen Konposita.
- Jede Klassenbibliothek und jedes Framework für Benutzerschnittstellen,
z.B. ET++ und Interviews, benutzt das Kompsitum-Muster.
- Das RTL-Smalltalk-Übersetzer-Frammwork.
Verwandte Muster
- Die Zuständigkeitskette als Verbingung zwischen Komponenten und Elternobjekt.
- Das Dekoriermuster wird oft mit Komposita verwendet.
- Durch das Fliegengewichtmuster Komponenten gemeinsam nutzen und Speicherplatz
sparen.
- Mit dem Iteratormuster ein Kompsitum traversierten (durchlaufen).
- Durch das Besuchermuster Operationen und Verhalten lokalisieren.
... [ Seminar Objektorientierter Entwurf] ... [ Thema Entwurfsmuster ] ... [ Strukturmuster: Fassade] ... [ Literaturverzeichnis ] ...