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.


komposi1.gif nicht gefunden...

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.


komposi2.gif nicht gefunden...

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


Struktur


komposi3.gif nicht gefunden...


Teilnehmer


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

  1. 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.
  2. 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.
  3. 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:
  1. 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.
  2. Gemeinsame Nutzung von Komponenten
    Dadurch können die Speicheranforderungen an das System gesenkt werden. Das Fliegengewichtmuster beschreibt eine Umsetzungsmöglichkeit.
  3. Maximieren der Komponentenschnittstelle
    Die Komponentenklasse sollte so viele gemeinsame Operationen der Blatt- und Kompositionsklassen definieren wie möglich (nötig).
  4. 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 :
    1. 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.
    2. 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.
  5. 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.
  6. 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.
  7. 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).
  8. 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


Verwandte Muster


... [ Seminar Objektorientierter Entwurf] ... [ Thema Entwurfsmuster ] ... [ Strukturmuster: Fassade] ... [ Literaturverzeichnis ] ...