Ein Blick auf das Composite-Designmuster

Neulich hörte ich Car Talk von National Public Radio , eine beliebte wöchentliche Sendung, in der Anrufer Fragen zu ihren Fahrzeugen stellen. Vor jeder Programmpause bitten die Moderatoren der Show die Anrufer, 1-800-CAR-TALK zu wählen, was 1-800-227-8255 entspricht. Ersteres ist natürlich viel leichter zu merken als Letzteres, auch weil die Wörter "CAR TALK" zusammengesetzt sind: zwei Wörter, die sieben Ziffern darstellen. Menschen finden es im Allgemeinen einfacher, mit Verbundwerkstoffen umzugehen, als mit ihren einzelnen Komponenten. Ebenso ist es bei der Entwicklung objektorientierter Software häufig praktisch, Verbundwerkstoffe so zu bearbeiten, wie Sie einzelne Komponenten bearbeiten. Diese Prämisse repräsentiert das Grundprinzip des zusammengesetzten Entwurfsmusters.das Thema dieser Java Design Patterns Rate.

Das zusammengesetzte Muster

Bevor wir uns mit dem zusammengesetzten Muster befassen, muss ich zuerst zusammengesetzte Objekte definieren : Objekte, die andere Objekte enthalten; Beispielsweise kann eine Zeichnung aus grafischen Grundelementen wie Linien, Kreisen, Rechtecken, Text usw. bestehen.

Java-Entwickler benötigen das Composite-Muster, da wir Composites häufig genauso bearbeiten müssen, wie wir primitive Objekte bearbeiten. Beispielsweise müssen grafische Grundelemente wie Linien oder Text gezeichnet, verschoben und in der Größe geändert werden. Wir möchten aber auch die gleiche Operation für Verbundwerkstoffe ausführen, z. B. Zeichnungen, die aus diesen Grundelementen bestehen. Im Idealfall möchten wir Operationen an primitiven Objekten und Verbundwerkstoffen auf genau dieselbe Weise ausführen, ohne zwischen beiden zu unterscheiden. Wenn wir zwischen primitiven Objekten und Verbundwerkstoffen unterscheiden müssen, um dieselben Operationen für diese beiden Objekttypen auszuführen, wird unser Code komplexer und schwieriger zu implementieren, zu warten und zu erweitern.

In Design Patterns beschreiben die Autoren das Composite-Muster folgendermaßen:

Verfassen Sie Objekte zu Baumstrukturen, um Teil-Ganz-Hierarchien darzustellen. Mit Composite können Clients einzelne Objekte und Objektzusammensetzungen einheitlich behandeln.

Das Implementieren des zusammengesetzten Musters ist einfach. Zusammengesetzte Klassen erweitern eine Basisklasse, die primitive Objekte darstellt. Abbildung 1 zeigt ein Klassendiagramm, das die Struktur des zusammengesetzten Musters veranschaulicht.

Im Klassendiagramm von Abbildung 1 habe ich Klassennamen aus der Diskussion über zusammengesetzte Muster von Design Pattern verwendet : ComponentStellt eine Basisklasse (oder möglicherweise eine Schnittstelle) für primitive Objekte dar und Compositestellt eine zusammengesetzte Klasse dar. Beispielsweise Componentkönnte die Klasse eine Basisklasse für grafische Grundelemente darstellen, während die CompositeKlasse eine DrawingKlasse darstellen könnte. Die LeafKlasse von Abbildung 1 repräsentiert ein konkretes primitives Objekt. Zum Beispiel eine LineKlasse oder eine TextKlasse. Die Methoden Operation1()und Operation2()stellen domänenspezifische Methoden dar, die sowohl von der Componentals auch von der CompositeKlasse implementiert sind.

Die CompositeKlasse verwaltet eine Sammlung von Komponenten. In der Regel werden CompositeMethoden implementiert, indem diese Sammlung durchlaufen und die entsprechende Methode für jede Componentin der Sammlung aufgerufen wird. Beispielsweise kann eine DrawingKlasse ihre draw()Methode folgendermaßen implementieren :

// Diese Methode ist eine zusammengesetzte Methode public void draw () {// Durchlaufe die Komponenten für (int i = 0; i <getComponentCount (); ++ i) {// Rufe einen Verweis auf die Komponente ab und rufe ihre Zeichnung auf Methode Component component = getComponent (i); component.draw (); }}

Für jede in der ComponentKlasse implementierte Methode implementiert die Klasse Compositeeine Methode mit derselben Signatur, die über die Komponenten des Verbundwerkstoffs iteriert, wie in der draw()oben aufgeführten Methode dargestellt.

Die CompositeKlasse erweitert die ComponentKlasse, sodass Sie einen Verbund an eine Methode übergeben können, die eine Komponente erwartet. Betrachten Sie beispielsweise die folgende Methode:

// Diese Methode ist in einer Klasse implementiert, die nichts mit den Klassen // Component und Composite zu tun hat. Public void repaint (Component component) {// Die Komponente kann ein Composite sein, aber da sie // die Component-Klasse erweitert, muss diese Methode nicht // zwischen Komponenten und Verbundwerkstoffen unterscheiden component.draw (); }}

Die vorhergehende Methode wird einer Komponente übergeben - entweder einer einfachen Komponente oder einem Composit - und ruft dann die draw()Methode dieser Komponente auf . Da die CompositeKlasse erweitert wird Component, muss die repaint()Methode nicht zwischen Komponenten und Verbundwerkstoffen unterscheiden. Sie ruft einfach die draw()Methode für die Komponente (oder den Verbundwerkstoff) auf.

Das Klassendiagramm für zusammengesetzte Muster in Abbildung 1 zeigt ein Problem mit dem Muster: Sie müssen zwischen Komponenten und Verbundwerkstoffen unterscheiden, wenn Sie auf a verweisen Component, und Sie müssen eine zusammensetzungsspezifische Methode aufrufen, z addComponent(). Normalerweise erfüllen Sie diese Anforderung, indem Sie isComposite()der ComponentKlasse eine Methode hinzufügen, z . Diese Methode gibt falsefür Komponenten zurück und wird in der zurückzugebenden CompositeKlasse überschrieben true. Darüber hinaus müssen Sie den ComponentVerweis auf eine CompositeInstanz wie folgt umwandeln:

... if (component.isComposite ()) {Composite Composite = (Composite) Komponente; osite.addComponent (someComponentThatCouldBeAComposite); } ...

Beachten Sie, dass der addComponent()Methode eine ComponentReferenz übergeben wird, die entweder eine primitive Komponente oder eine zusammengesetzte Komponente sein kann. Da diese Komponente ein Verbund sein kann, können Sie Komponenten zu einer Baumstruktur zusammensetzen, wie aus dem oben genannten Zitat aus Entwurfsmuster hervorgeht .

Abbildung 2 zeigt eine alternative Implementierung eines zusammengesetzten Musters.

Wenn Sie das zusammengesetzte Muster von Abbildung 2 implementieren, müssen Sie nie zwischen Komponenten und Verbundwerkstoffen unterscheiden und keinen ComponentVerweis auf eine CompositeInstanz erstellen. Das oben aufgeführte Codefragment reduziert sich also auf eine einzelne Zeile:

... component.addComponent (someComponentThatCouldBeAComposite); ...

Aber was sollte der tun , wenn sich die ComponentReferenz im vorhergehenden Codefragment nicht auf a bezieht ? Dies ist ein Hauptstreitpunkt bei der Implementierung des zusammengesetzten Musters in Abbildung 2. Da primitive Komponenten keine anderen Komponenten enthalten, ist das Hinzufügen einer Komponente zu einer anderen Komponente nicht sinnvoll. Daher kann die Methode entweder unbeaufsichtigt fehlschlagen oder eine Ausnahme auslösen. In der Regel wird das Hinzufügen einer Komponente zu einer anderen primitiven Komponente als Fehler angesehen. Daher ist das Auslösen einer Ausnahme möglicherweise die beste Vorgehensweise.CompositeaddComponent()Component.addComponent()

Welche Implementierung eines zusammengesetzten Musters - die in Abbildung 1 oder die in Abbildung 2 - funktioniert am besten? Dies ist unter Composite-Pattern-Implementierern immer ein Thema, über das große Debatten geführt werden. Design Patterns bevorzugt die Implementierung in Abbildung 2, da Sie niemals zwischen Komponenten und Containern unterscheiden müssen und niemals eine Umwandlung durchführen müssen. Persönlich bevorzuge ich die Implementierung von Abbildung 1, da ich eine starke Abneigung gegen die Implementierung von Methoden in einer Klasse habe, die für diesen Objekttyp keinen Sinn ergeben.

Nachdem Sie das zusammengesetzte Muster verstanden haben und wissen, wie Sie es implementieren können, untersuchen wir ein Beispiel für ein zusammengesetztes Muster mit dem JSP-Framework (Apache Struts JavaServer Pages).

Das zusammengesetzte Muster und die Strebenfliesen

Das Apache Struts-Framework enthält eine JSP-Tag-Bibliothek, die als Tiles bezeichnet wird und mit der Sie eine Webseite aus mehreren JSPs erstellen können. Tiles ist eine Implementierung des CompositeView-Musters J2EE (Java 2 Platform, Enterprise Edition), das selbst auf dem Composite-Muster Design Patterns basiert . Bevor wir die Relevanz des zusammengesetzten Musters für die Tiles-Tag-Bibliothek diskutieren, wollen wir zunächst die Gründe für Tiles und deren Verwendung überprüfen. Wenn Sie bereits mit Strebenkacheln vertraut sind, können Sie die folgenden Abschnitte überfliegen und mit dem Lesen unter "Verwenden des Verbundmusters mit Strebenkacheln" beginnen.

Hinweis: Weitere Informationen zum J2EE CompositeView-Muster finden Sie in meinem Artikel " Webanwendungskomponenten, die mit Composite View einfach gemacht wurden " ( JavaWorld, Dezember 2001).

Designer erstellen häufig Webseiten mit einer Reihe diskreter Bereiche. Beispielsweise umfasst die Webseite von Abbildung 3 eine Seitenleiste, eine Kopfzeile, einen Inhaltsbereich und eine Fußzeile.

Websites enthalten häufig mehrere Webseiten mit identischen Layouts, z. B. das Seitenleisten- / Kopf- / Inhalts- / Fußzeilenlayout in Abbildung 3. Mit Struts Tiles können Sie sowohl Inhalt als auch Layout auf mehreren Webseiten wiederverwenden. Bevor wir diese Wiederverwendung diskutieren, wollen wir sehen, wie das Layout von Abbildung 3 traditionell nur mit HTML implementiert wird.

Implementieren Sie komplexe Layouts von Hand

Beispiel 1 zeigt, wie Sie die Webseite von Abbildung 3 mit HTML implementieren können:

Beispiel 1. Ein komplexes Layout, das von Hand implementiert wurde

    Komplexe Layouts von Hand implementieren <% - Eine Tabelle enthält den gesamten Inhalt dieser Seite -%>
   
Links

Zuhause

Produkte

Downloads

weiße Papiere

Kontaktiere uns

Willkommen bei Sabreware, Inc.
Seitenspezifischer Inhalt finden Sie hier

Danke für's vorbeikommen!

Die vorhergehende JSP hat zwei Hauptnachteile: Erstens ist der Inhalt der Seite in die JSP eingebettet, sodass Sie nichts davon wiederverwenden können, obwohl Seitenleiste, Kopf- und Fußzeile auf vielen Webseiten wahrscheinlich gleich sind. Zweitens ist das Layout der Seite auch in diese JSP eingebettet, sodass Sie es ebenfalls nicht wiederverwenden können, obwohl viele andere Webseiten auf derselben Website dasselbe Layout verwenden. Wir können die Aktion verwenden, um den ersten Nachteil zu beheben, wie ich als nächstes diskutiere.

Implementieren Sie komplexe Layouts mit JSP-Includes

Beispiel 2 zeigt eine Implementierung der Webseite von Abbildung 3, die Folgendes verwendet :