Start
Unternehmen
Buch-Katalog
Seminare
Leserservice
Comelio-Blog
Datenbanken
SQL
MS SQL Server
Oracle
PHP
UML
C#.NET

Operator-Überladung

Konvertierungen

Schnittstellen

Abstrakte Klassen

Delegation

Indexer

Code-Behind

Adapter-Muster

Dekorierer-Muster

Kompositum-Muster

XML Schema
XSLT

Übersicht

Comelio GmbH
Rellinghauser Straße 10
D-45128 Essen
Deutschland
Fon: 0201-437517-0
Fax: 0201-437517-10
info@comelio.com

Comelio GmbH
Goethestraße 34
D-13086 Berlin
Deutschland
info@comelio.com

Comelio GmbH (Ecos)
Glockengießerwall 17
D-20095 Hamburg
Deutschland
info@comelio.com

Comelio GmbH (Ecos)
Mainzer Landstraße 27-31
D-60329 Frankfurt
Deutschland
info@comelio.com

Comelio GmbH (Ecos)
Stiglmaierplatz/Dachauer Str. 37
D-80335 München
Deutschland
info@comelio.com

Comelio GmbH (Ecos)
Liebknechtstr. 33
D-70565 Stuttgart
Deutschland
info@comelio.com

Comelio GmbH
Nevinghoff 16
D-48147 Münster
Deutschland

Comelio GmbH
Friedrich - List - Platz 1
D-04103 Leipzig
Deutschland

Comelio GmbH
St. Johanner Strasse 41-43
D-66111 Saarbrücken
Deutschland

Comelio GmbH
Kaiser-Wilhem-Ring 27–29
D-50672 Köln
Deutschland

Comelio GmbH
Münsterstraße 248
D-40470 Düsseldorf
Deutschland

Comelio GmbH
Fürther Strasse
D-90429 Nürnberg
Deutschland

Comelio GmbH

Bremen
Deutschland

Comelio-Blog > C#.NET > Kompositum-Muster

Entwurfsmuster (Design Patterns) in C#.NET: Kompositum

Ein Muster, das dieser Artikel als Beispiel für den Einsatz von Schnittstellen vorstellen will, ist das Kompositum-Muster. Hier soll das Ziel umgesetzt werden, dass man Einheiten und zusammengesetzte Einheiten / Komposita unterscheidet. Das heißt, Objekte können wiederum andere Objekte enthalten. Dies ist, wenn man einen Warenkorb mit verschiedenen Produkt-Objekten zum Vergleich heranzieht, zunächst nicht so eine herausragende Besonderheit. Dies liegt an der grundsätzlichen Verschiedenheit von Warenkorb und Produkt. Eine weitere Voraussetzung, die in Situation, in welcher das Muster zum Einsatz kommen kann, zutreffen muss, ist die gleichartige Verarbeitung vom Kompositum und den einzelnen Einheiten.

Kontakt

Anrede* Herr Frau
Vorname*
Nachname*
Firma
E-Mail*
Tel-Nr.
Bereich*
Freitext

Design Patterns: Kompositum / Composite in C#.NET

Ein weiteres Muster, das wir als Beispiel für den Einsatz von Schnittstellen vorstellen wollen, ist das Kompositum-Muster. Hier soll das Ziel umgesetzt werden, dass man Einheiten und zusammengesetzte Einheiten / Komposita unterscheidet. Das heißt, Objekte können wiederum andere Objekte enthalten. Dies ist, wenn man einen Warenkorb mit verschiedenen Produkt-Objekten zum Vergleich heranzieht, zunächst nicht so eine herausragende Besonderheit. Dies liegt an der grundsätzlichen Verschiedenheit von Warenkorb und Produkt. Eine weitere Voraussetzung, die in Situation, in welcher das Muster zum Einsatz kommen kann, zutreffen muss, ist die gleichartige Verarbeitung vom Kompositum und den einzelnen Einheiten.

Im Beispiel der geometrischen Körper kann man sich vorstellen, dass man eine Gruppe von geometrischen Objekten besitzt, die ebenfalls solche Methoden wie errechneFlaeche unterstützen sollen. Ob man also die Fläche von einem einzigen Objekt ausrechnen lassen will, oder ob diese Rechnung für alle Objekte der Gruppe durchgeführt werden soll, lässt sich über das Muster einrichten. Dazu muss ja lediglich im Kompositum die gleiche Methode implementiert werden wie im einzelnen Objekt. Dabei ist die Implementierung grundlegend verschieden, weil das Kompositum alle enthaltenen Objekte durchläuft und die entsprechende Methode aufruft, doch der Rückgabewert und seine Bedeutung für die Anwendung (Fläche, Kantenlänge, Volumen) sind die gleichen.

Zunächst wird also eine Schnittstelle benötigt, die sowohl für Einheiten als auch für Komposita passende Komponenten fordert. Dies ist zum einen die bereits bekannte Methode errechneFlaeche, zum anderen sind dies zwei neue Methode für das Hinzufügen und Entfernen von einzelnen Objekten. An diesen beiden Methoden ist interessant, dass sie jeweils Objekte vom Typ der Schnittstelle, also von sich erwarten. Hier liegt eine reflexive Beziehung vor, welche die Zusammensetzung von Objekten unterstützt.

public interface IKoerper {
   // Eigenschaften
   int laenge { get; }
   int breite { get; }
   int hoehe  { get; }
   int anzahl { get; }
   // Methoden
   double errechneFlaeche();
   void hinzufuegen(IKoerper koerper);
   void entfernen(IKoerper koerper);
}
Schnittstelle für ein Kompositum

Die Klasse Quadrat hat zunächst den erwarteten Aufbau, weswegen wir den Quelltext etwas zusammengestaucht haben, damit er übersichtlicher wird. Da sie die gerade vorgeführte Schnittstelle mit den beiden besonderen Methoden zum Hinzufügen und Entfernen von Objekten implementieren muss, sind diese natürlich auch vorhanden, wobei sie allerdings keine sinnvolle Aktion durchführen können. Dies kann man entweder durch einen leeren Anweisungsblock ausdrücken, was allerdings nicht so gelungen ist, durch einen booleschen Rückgabewert, der jedoch in der Schnittstelle nicht gefordert wurde, oder durch eine Ausnahme. Dies ist eine Fehlermeldung, auf deren Verwendung wir im nächsten Kapitel eingehen werden. Diese Ausnahme ist zwar eine gute Lösung, doch stellt sie eigentlich einen Schönheitsfehler dar, welchen wir im nächsten Beispiel beheben werden. Methoden nur zu implementieren, damit einer Schnittstelle Genüge getan wird und um einige Methoden sowohl auf Einheiten wie auf Zusammensetzungen auszuführen, ist nicht gerade hübsch aufgebaute Software.

public class Quadrat : IKoerper {  
   // Felder
   private int _laenge;
   // Eigenschaften
   public int laenge { get { return _laenge; } }
   public int hoehe { get { return 0; } }
   public int breite { get { return _laenge; } }
   public int anzahl { get { return 1; } }
   // Methoden
   public Quadrat(int laenge) {
      _laenge = laenge;
   }
   public double errechneFlaeche() {
       return laenge * laenge;
   }
   public void hinzufuegen(IKoerper koerper){
       throw new Exception("Kein Kompositum.");
   }
   public void entfernen(IKoerper koerper){
       throw new Exception("Kein Kompositum.");
   }
}
Einzelne Einheit

Die Klasse Kompositum dagegen kann mit den gerade kritisch beäugten Methoden hinzufuegen und entfernen dagegen überaus wichtige Aktionen durchführen, nämlich tatsächlich Objekte vom Typ IKoerper (Quadrate, Rechtecke, Quader) in eine private ArrayList schreiben bzw. aus dieser wieder löschen. Hier macht auch die Eigenschaft anzahl Sinn, die in den anderen Klassen immer nur den Wert 1 zurücklieferte, weil natürlich eine Einheit nur aus einem Objekt besteht, ein Kompositum allerdings aus mehreren.

Neben den Methoden zum Bearbeiten der Objektsammlung gibt es auch noch die Methode errechneFlaeche, welche sich durch eine ganz andere Implementierung auszeichnet als in den Klassen für Einheiten vom Typ IKoerper. Da die Sammlung als solche keine Fläche hat, sondern nur die in ihr untergebrachten Objekte, müssen in einer foreach-Schleife die einzelnen Objekte durchlaufen werden. Da sie alle die gleiche Schnittstelle implementieren, lässt sich ihr polymorphes Verhalten nutzen und die jeweilige errechneFlaeche-Methode aufrufen, um die Werte als Summe zurückzugeben.

public class Kompositum : IKoerper {  
   // Felder
   private ArrayList _kompositum;
   // Eigenschaften
   public int laenge { get { return 0; } }
    public int hoehe { get { return 0; } }
    public int breite { get { return 0; } }
    public int anzahl {
        get { return _kompositum.Count; }
    }
   // Methoden
   public Kompositum() {
       _kompositum = new ArrayList();
   }
   public double errechneFlaeche() {
       double flaeche = 0;
       foreach (IKoerper koerper in _kompositum) {
           flaeche += koerper.errechneFlaeche();
       }
       return flaeche;
   }
   public void hinzufuegen(IKoerper koerper){
       _kompositum.Add(koerper);
   }
   public void entfernen(IKoerper koerper){
       _kompositum.Remove(koerper);
   }
}
Zusammensetzung

Ein einfacher Test zeigt die Funktionstüchtigkeit der gesamten Konstruktion. Zunächst erstellt man wenigstens zwei Objekte vom Typ Quadrat und Rechteck, die dann zu einem Ganzen zusammengefügt werden. Dieses Kompositum wiederum soll nun die Summe aller Flächen und damit seine eigene Fläche zurückgeben. Da die Kantenlängen sehr klein gewählt wurden, lässt sich die entstehende Summe leicht als richtig überprüfen.

Quadrat quadrat = new Quadrat(3);
Rechteck rechteck = new Rechteck(3, 4);
Kompositum kompositum = new Kompositum();
kompositum.hinzufuegen(quadrat);
kompositum.hinzufuegen(rechteck);
ausgabe.Text += kompositum.anzahl + ": ";
ausgabe.Text += quadrat.errechneFlaeche() + " + " + 
                rechteck.errechneFlaeche() + " = ";
ausgabe.Text += kompositum.errechneFlaeche();
Verwendung von Einzelstücken und Zusammensetzungen

Man erhält als Ausgabe: 2: 9 + 12 = 21. Einige der Entwurfsmuster weisen überaus charakteristische UML-Diagramme auf. Teilweise wie beim Singleton-Muster sind sie aufgrund der Übersichtlichkeit und Selbstreflexivität gut zu erkennen, teilweise aufgrund von eher selten erscheinenden Beziehungen wie hier im Kompositum. Auf Basis einer gemeinsamen Schnittstelle implementiert man so viele Klassen für Einheiten und Komposita wie einem notwendig erscheint. Für die Komposita gibt es eine weitere Aggregationsverbindung zur Schnittstelle, mit deren Hilfe ausgedrückt wird, dass das Kompositum Objekte vom Typ der Schnittstelle erwartet und speichern kann.

Kompositum-Muster

Kompositum-Muster

Obwohl das Design elegant ist und das Muster eine Lösung für viele Probleme bietet, die bei der Abbildung von baumartigen Strukturen (Ordnern, Objektgruppen, XML-Elementen) hilfreich sein können, so ist das Auslösen von Ausnahmen doch insoweit ein Problem, weil man außen immer darauf gefasst sein muss, dass man gar nicht mit einer Zusammensetzung, sondern mit einer Einheit arbeitet. Dieses Problem konnte beim Experiment nicht auftreten, weil hier die verschiedenen Objekte statisch gebunden wurden. Man hat zunächst ein Quadrat, dann ein Rechteck und zum Schluss erst ein Kompositum erstellt. Man wäre eigentlich gar nicht darauf gekommen, einem Rechteck ein Quadrat hinzuzufügen. Dies liegt daran, weil man die Objektnatur an den Klassennamen eigentlich sehr gut erkennen kann. Nicht immer ist dies der Fall, weil nicht immer die Sammlungen so deutlich darauf hinweisen.

In diesem Fall lohnt sich ein etwas anderer Aufbau. Dieser verhindert nicht, dass man wenigstens den Objekttyp testen muss, um seine Natur herauszufinden, doch dies ist möglicherweise einfacher als mit einem try- und catch-Block jeweils die Sammlungsmodifikation durchzuführen. Ein kleiner Wermutstropfen bleibt also auch bei der jetzt vorgestellten Lösung, allerdings spart man sich bei der Erstellung unnötige Methoden und kann außen bei der Verwendung mit einer einfachen Fallunterscheidung arbeiten.

Die Lösung sieht so aus, dass man einfach zwei Schnittstellen erstellt, von denen die erste alles enthält, was Einheiten und Sammlungen gemein ist. Die zweite dagegen enthält nur solche Komponenten, die speziell für Sammlungen interessant ist. Durch den hierarchischen Aufbau sind dennoch die verschiedenen für Einheiten notwendigen Komponenten auch in den basierend auf der zweiten Schnittstelle erstellten Klassen enthalten. Die Quelltexte sind stark gekürzt, um die wesentlichen Änderungen zwischen der ersten und zweiten Version aufzuzeigen.

public interface IKoerper {
   // Eigenschaften
   // Methoden
   double errechneFlaeche();
}

public interface IKoerperKompositum : IKoerper  {
   // Methoden
   void hinzufuegen(IKoerper koerper);
   void entfernen(IKoerper koerper);
}
Getrennte Schnittstellen

Die Benutzung beider Schnittstellen erfolgt so, dass solche Klassen für Einheiten wie Quadrat, Rechteck oder Quader die IKoerper-Schnittstelle implementieren, während die zweite Schnittstelle IKoerperKompositum von Sammlungen implementiert wird.

public class Quadrat : IKoerper {  
   // Felder und Eigenschaften
   // Methoden mit Konstruktor und errechneFlaeche
   // ohne hinzufuegen und entfernen
}

public class Kompositum : IKoerperKompositum {  
   // Felder mit _kompositum und Eigenschaften
   // Methoden mit Konstruktor und errechneFlaeche
   // sowie hinzufuegen und entfernen
}
Geordneter Klassenaufbau

Im UML-Diagramm erkennt man den für das Kompositum-Muster charakteristischen Aufbau, wobei nun allerdings die Schnittstelle für Sammlungen an der Stelle der ehemaligen Kompositum-Klasse sitzt und sowohl die Implementierung einer Schnittstelle als auch die Aggregationsbeziehung mit der gleichen Schnittstelle aufweist. Erst von dieser Schnittstelle ausgehend, schließen sich Sammlungsklassen an, von denen genau eine existiert, die für die Sammlungen notwendigen Methoden wie hinzufuegen und entfernen implementieren.

Erweitertes Kompositum

Erweitertes Kompositum

    Comelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt LudwigshafenComelio GmbH C#.NET - Kompositum-Muster - Design Patterns / Entwurfsmuster Microsoft C#.NET Tutorial Syntax Beispiel .NET Code Entwurfsmuster Programmierung Anleitung Aachen Ingolstadt Ol Stuttgart Koblenz Lübeck Erlangen Berlin Kiel Mannheim Zwickau Hamburg Würzuburg Bochum Freiburg Heidelberg Köln Magdeburg Hannover Andernach Koblenz Wolfsburg Bremen München Bonn Göttingen Leipzig Kassel Rügen Frankfurt Ludwigshafen
Seminare