Neulich hörte ich die Sendung Car Talk des National Public Radio, eine beliebte wöchentliche Sendung, in der Anrufer Fragen zu ihren Fahrzeugen stellen. Vor jeder Sendepause bitten die Moderatoren die Anrufer, die Nummer 1-800-CAR-TALK zu wählen, die der Nummer 1-800-227-8255 entspricht. Erstere ist natürlich viel leichter zu merken als letztere, was zum Teil daran liegt, dass die Worte „CAR TALK“ ein Kompositum sind: zwei Wörter, die für sieben Ziffern stehen. Menschen finden es im Allgemeinen einfacher, mit Komposita umzugehen, als mit ihren einzelnen Bestandteilen. Auch bei der Entwicklung objektorientierter Software ist es oft bequemer, Komposita genauso zu manipulieren wie einzelne Komponenten. Diese Prämisse stellt das Grundprinzip des Composite Design Patterns dar, dem Thema dieser Java Design Patterns-Folge.

Das Composite Pattern

Bevor wir uns mit dem Composite Pattern beschäftigen, muss ich zunächst Composite-Objekte definieren: Objekte, die andere Objekte enthalten; zum Beispiel kann eine Zeichnung aus grafischen Primitiven wie Linien, Kreisen, Rechtecken, Text usw. bestehen.

Java-Entwickler brauchen das Composite-Muster, weil wir Composites oft auf die gleiche Weise manipulieren müssen wie primitive Objekte. Zum Beispiel müssen grafische Primitive wie Linien oder Text gezeichnet, verschoben und in der Größe verändert werden. Aber wir möchten die gleichen Operationen auch an Composites, wie z. B. Zeichnungen, durchführen, die aus diesen Primitiven bestehen. Im Idealfall möchten wir Operationen an primitiven Objekten und Komposita auf genau dieselbe Weise durchführen, ohne zwischen den beiden zu unterscheiden. Wenn wir zwischen primitiven Objekten und Composites unterscheiden müssen, um dieselben Operationen mit diesen beiden Objekttypen durchzuführen, würde unser Code komplexer und schwieriger zu implementieren, zu warten und zu erweitern sein.

In Design Patterns beschreiben die Autoren das Composite-Muster wie folgt:

Zusammengesetzte Objekte in Baumstrukturen, um Teil-Ganzes-Hierarchien darzustellen. Mit Composite können Clients einzelne Objekte und Kompositionen von Objekten einheitlich behandeln.

Die Implementierung des Composite-Musters ist einfach. Composite-Klassen erweitern eine Basisklasse, die primitive Objekte repräsentiert. Abbildung 1 zeigt ein Klassendiagramm, das die Struktur des Composite-Musters veranschaulicht.

Abbildung 1. Ein Klassendiagramm nach dem Composite-Muster

Im Klassendiagramm von Abbildung 1 habe ich Klassennamen aus der Diskussion über das Composite-Muster von Design Pattern verwendet: Component steht für eine Basisklasse (oder möglicherweise eine Schnittstelle) für primitive Objekte, und Composite steht für eine zusammengesetzte Klasse. Beispielsweise könnte die Klasse Component eine Basisklasse für grafische Primitive darstellen, während die Klasse Composite eine Drawing-Klasse darstellen könnte. Die Klasse Leaf in Abbildung 1 steht für ein konkretes primitives Objekt, zum Beispiel eine Line-Klasse oder eine Text-Klasse. Die Methoden Operation1() und Operation2() stellen domänenspezifische Methoden dar, die von den Klassen Component und Composite implementiert werden.

Die Klasse Composite verwaltet eine Sammlung von Komponenten. Normalerweise werden Composite-Methoden implementiert, indem über diese Sammlung iteriert wird und die entsprechende Methode für jede Component in der Sammlung aufgerufen wird. Zum Beispiel könnte eine Drawing-Klasse ihre draw()-Methode wie folgt implementieren:

Für jede Methode, die in der Component-Klasse implementiert ist, implementiert die Composite-Klasse eine Methode mit der gleichen Signatur, die über die Komponenten des Composites iteriert, wie die oben aufgeführte draw()-Methode zeigt.

Die Klasse Composite erweitert die Klasse Component, so dass Sie einer Methode, die eine Komponente erwartet, ein Kompositum übergeben können; betrachten Sie zum Beispiel die folgende Methode:

// This method is implemented in a class that's unrelated to the// Component and Composite classespublic void repaint(Component component) { // The component can be a composite, but since it extends // the Component class, this method need not // distinguish between components and composites component.draw();}

Der vorhergehenden Methode wird eine Komponente übergeben – entweder eine einfache Komponente oder ein Kompositum – und ruft dann die Methode draw() dieser Komponente auf. Da die Klasse Composite die Klasse Component erweitert, muss die Methode repaint() nicht zwischen Komponenten und Composites unterscheiden – sie ruft einfach die Methode draw() für die Komponente (oder das Composite) auf.

Das Klassendiagramm des Composite-Musters in Abbildung 1 verdeutlicht ein Problem mit dem Muster: Sie müssen zwischen Komponenten und Composites unterscheiden, wenn Sie eine Component referenzieren, und Sie müssen eine Composite-spezifische Methode aufrufen, wie addComponent(). In der Regel erfüllt man diese Anforderung, indem man der Klasse Component eine Methode, wie isComposite(), hinzufügt. Diese Methode gibt false für Komponenten zurück und wird in der Klasse Composite überschrieben, um true zurückzugeben. Zusätzlich müssen Sie die Component-Referenz in eine Composite-Instanz umwandeln, etwa so:

Beachten Sie, dass der addComponent()-Methode eine Component-Referenz übergeben wird, die entweder eine primitive Komponente oder ein Composite sein kann. Da es sich bei dieser Komponente um eine zusammengesetzte Komponente handeln kann, können Sie die Komponenten in einer Baumstruktur zusammensetzen, wie in dem oben erwähnten Zitat aus Design Patterns angegeben.

Abbildung 2 zeigt eine alternative Implementierung des Composite-Musters.

Abbildung 2. Ein alternatives Klassendiagramm des Composite-Musters

Wenn Sie das Composite-Muster aus Abbildung 2 implementieren, müssen Sie nie zwischen Komponenten und Composites unterscheiden, und Sie müssen eine Component-Referenz nicht auf eine Composite-Instanz casten. Das oben aufgeführte Codefragment reduziert sich also auf eine einzige Zeile:

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

Aber wenn der Component-Verweis im vorangegangenen Codefragment nicht auf eine Composite-Instanz verweist, was soll dann die addComponent() tun? Dies ist ein wesentlicher Streitpunkt bei der Implementierung des Composite-Musters in Abbildung 2. Da primitive Komponenten keine anderen Komponenten enthalten, macht das Hinzufügen einer Komponente zu einer anderen Komponente keinen Sinn, so dass die Methode Component.addComponent() entweder stillschweigend fehlschlagen oder eine Ausnahme auslösen kann. Normalerweise wird das Hinzufügen einer Komponente zu einer anderen primitiven Komponente als Fehler angesehen, so dass das Auslösen einer Ausnahme vielleicht die beste Vorgehensweise ist.

Welche Implementierung des Composite-Musters – die in Abbildung 1 oder die in Abbildung 2 – funktioniert also am besten? Design Patterns bevorzugt die Implementierung in Abbildung 2, weil man nie zwischen Komponenten und Containern unterscheiden muss und weil man nie einen Cast durchführen muss. Ich persönlich bevorzuge die Implementierung von Abbildung 1, da ich eine starke Abneigung gegen die Implementierung von Methoden in einer Klasse habe, die für diesen Objekttyp nicht sinnvoll sind.

Nachdem Sie nun das Composite-Muster und seine Implementierung verstanden haben, lassen Sie uns ein Beispiel für das Composite-Muster mit dem Apache Struts JavaServer Pages (JSP) Framework untersuchen.

Das Composite-Muster und Struts Tiles

Das Apache Struts-Framework enthält eine JSP-Tag-Bibliothek, bekannt als Tiles, mit der Sie eine Webseite aus mehreren JSPs zusammenstellen können. Tiles ist eigentlich eine Implementierung des J2EE (Java 2 Platform, Enterprise Edition) CompositeView-Musters, das wiederum auf dem Design Patterns Composite-Muster basiert. Bevor wir die Relevanz des Composite-Musters für die Tiles-Tag-Bibliothek erörtern, wollen wir zunächst die Gründe für Tiles und seine Verwendung erläutern. Wenn Sie bereits mit Struts Tiles vertraut sind, können Sie die folgenden Abschnitte überspringen und bei „Use the Composite Pattern with Struts Tiles“ (Verwendung des Composite-Musters mit Struts Tiles) beginnen.

Hinweis: Sie können mehr über das J2EE CompositeView-Muster in meinem Artikel „Web Application Components Made Easy with Composite View“ (JavaWorld, Dezember 2001) lesen.

Designer konstruieren Webseiten oft mit einer Reihe von diskreten Bereichen; die Webseite in Abbildung 3 besteht beispielsweise aus einer Seitenleiste, einer Kopfzeile, einem Inhaltsbereich und einer Fußzeile.

Abbildung 3. Das Composite-Muster und die Struts-Kacheln. Klicken Sie auf die Miniaturansicht, um das Bild in voller Größe zu sehen.

Websites enthalten oft mehrere Webseiten mit identischen Layouts, wie das Layout von Seitenleiste/Kopfzeile/Inhaltsbereich/Fußzeile in Abbildung 3. Mit Struts Tiles können Sie sowohl Inhalt als auch Layout auf mehreren Webseiten wiederverwenden. Bevor wir diese Wiederverwendung besprechen, sehen wir uns an, wie das Layout von Abbildung 3 traditionell mit HTML allein implementiert wird.

Komplexe Layouts von Hand implementieren

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

Beispiel 1. Ein komplexes Layout von Hand implementiert

Das vorangegangene JSP hat zwei große Nachteile: Erstens ist der Inhalt der Seite in die JSP eingebettet, so dass Sie nichts davon wiederverwenden können, obwohl die Seitenleiste, die Kopfzeile und die Fußzeile wahrscheinlich auf vielen Webseiten gleich sind. Zweitens ist auch das Layout der Seite in diese JSP eingebettet, so dass Sie es ebenfalls nicht wiederverwenden können, auch wenn viele andere Webseiten derselben Website dasselbe Layout verwenden. Mit der <jsp:include>-Aktion lässt sich der erste Nachteil beheben, wie ich im Folgenden erläutere.

Komplexe Layouts mit JSP-Includes implementieren

Beispiel 2 zeigt eine Implementierung der Webseite in Abbildung 3, die <jsp:include> verwendet:

Beispiel 2. Ein komplexes Layout, das mit JSP implementiert wurde, enthält

Die vorangehende JSP enthält den Inhalt anderer JSPs mit <jsp:include>. Da ich diesen Inhalt in separaten JSPs gekapselt habe, können Sie ihn für andere Webseiten wiederverwenden:

Beispiel 3. sidebar.jsp

Der Vollständigkeit halber habe ich unten die JSPs aufgelistet, die von der vorhergehenden JSP eingeschlossen werden:

Beispiel 4. header.jsp

<font size='6'>Welcome to Sabreware, Inc.</font><hr>

Beispiel 5. content.jsp

<font size='4'>Page-specific content goes here</font>

Beispiel 6. footer.jsp

<hr>Thanks for stopping by!

Auch wenn die JSP von Beispiel 2 <jsp:include> verwendet, um Inhalte wiederzuverwenden, kann man das Layout der Seite nicht wiederverwenden, da es in dieser JSP fest kodiert ist. Mit Struts Tiles können Sie sowohl den Inhalt als auch das Layout wiederverwenden, wie im nächsten Abschnitt gezeigt wird.

Komplexe Layouts mit Struts Tiles implementieren

Beispiel 7 zeigt die Webseite in Abbildung 3, die mit Struts Tiles implementiert wurde:

Beispiel 7. Verwenden Sie Struts Tiles, um das Layout zu kapseln

Die vorangehende JSP verwendet das <tiles:insert>-Tag, um die JSP von Abbildung 3 zu erstellen. Diese JSP wird durch eine Kacheldefinition namens sidebar-header-footer-definition definiert. Diese Definition befindet sich in der Tiles-Konfigurationsdatei, die in diesem Fall WEB-INF/tiles-defs.xml heißt und in Beispiel 8 aufgeführt ist:

Beispiel 8. WEB-INF/tiles-defs.xml

Die vorangehende Tiles-Definition spezifiziert das Seitenlayout, gekapselt in header-footer-sidebar-layout.jsp, und den Inhalt der Seite, gekapselt in sidebar.jsp, header.jsp, content.jsp und footer.jsp, wie in den Beispielen 3-6 aufgeführt. Beispiel 9 listet die JSP auf, die das Layout definiert: header-footer-sidebar-layout.jsp:

Beispiel 9. header-footer-sidebar-layout.jsp

Die vorangehende JSP kapselt das Layout und fügt den Inhalt entsprechend den Werten ein, die für die Regionen Sidebar, Editor, Content und Footer in der Tiles-Definitionsdatei angegeben sind, was die Wiederverwendung sowohl des Inhalts als auch des Layouts erleichtert. Sie könnten beispielsweise eine weitere Tiles-Definition mit demselben Layout, derselben Seitenleiste, demselben Editor und derselben Fußzeile, aber anderem Inhalt definieren:

Um die durch die Tiles-Definition a-different-sidebar-header-footer-definition definierte JSP zu erstellen, verwenden Sie den <tiles:insert>-Tag wie folgt:

Dank Struts Tiles können Sie sowohl Inhalt als auch Layout wiederverwenden, was sich für Websites mit vielen JSPs, die Layout und einige Inhalte gemeinsam nutzen, als unschätzbar erweist. Wenn Sie sich jedoch den Code aus den Beispielen 7-9 genau ansehen, werden Sie feststellen, dass das Layout für die Sidebar-Region in sidebar.jsp, das in Beispiel 3 aufgeführt ist, fest kodiert ist. Das bedeutet, dass Sie dieses Layout nicht wiederverwenden können. Glücklicherweise implementiert die Tiles-Tag-Bibliothek das Composite-Muster, mit dem wir eine Tiles-Definition – anstelle einer JSP – für eine Region angeben können. Im nächsten Abschnitt erkläre ich, wie man diese Composite-Muster-Implementierung verwendet.

Verwenden Sie das Composite-Muster mit Struts Tiles

Struts Tiles implementiert das Composite-Muster, wobei die Klasse Component durch JSPs und die Klasse Composite durch eine Tiles-Definition dargestellt wird. Mit dieser Implementierung können Sie entweder eine JSP (eine Komponente) oder eine Tiles-Definition (ein Composite) als Inhalt für eine JSP-Region angeben. Beispiel 10 veranschaulicht diese Funktion:

Beispiel 10. WEB-INF/tiles-defs.xml: Verwenden Sie das Composite-Muster

Die vorangehende Tiles-Konfigurationsdatei definiert zwei Tiles-Definitionen: sidebar-definition und sidebar-header-footer-definition. sidebar-definition wird als Wert für den Seitenleistenbereich in sidebar-header-footer-definition angegeben. Sie können es als solches angeben, weil Tiles das Composite-Muster implementiert, indem Tiles eine Definition (eine Composite, die eine JSP-Sammlung ist) angibt, wo Sie normalerweise eine einzelne JSP (die eine Component ist) angeben würden.

Das Layout der Seitenleiste ist in der sidebar-layout.jsp von Beispiel 11 gekapselt:

Beispiel 11. sidebar-layout.jsp

Beispiel 12 führt flags.jsp auf, das als Inhalt für den top-Bereich der Seitenleiste angegeben ist, und Beispiel 13 führt sidebar-links.jsp auf, das als bottom-Bereich der Seitenleiste angegeben ist:

Beispiel 12. flags.jsp

Beispiel 13. sidebar-links.jsp

Jetzt kann die sidebar-definition andere Regionen mit einer oberen und unteren Komponente definieren, obwohl Sie diese Definition wahrscheinlich in etwas allgemeineres wie top-bottom-definition umbenennen sollten.

Heutzutage sind alle Composites

Das Composite-Muster ist bei Präsentations-Frameworks wie Swing und Struts sehr beliebt, da es die Verschachtelung von Containern ermöglicht, indem Komponenten und ihre Container genau gleich behandelt werden. Struts Tiles verwendet das Composite-Muster, um eine einfache JSP oder eine Tiles-Definition – eine Sammlung von JSPs – als Inhalt einer Kachel anzugeben. Das ist eine mächtige Fähigkeit, die die Verwaltung großer Websites mit unterschiedlichen Layouts erleichtert.

Der folgende Abschnitt „Hausaufgaben vom letzten Mal“ erweitert die Diskussion dieses Artikels, indem er die vorhergehende Anwendung mit einer Struts-Aktion und der JSP Standard Tag Library (JSTL) internationalisiert.

Hausaufgaben

Diskutieren Sie, wie Swing das Composite-Muster mit den Klassen Component und Container implementiert.

Hausaufgabe vom letzten Mal

In der letzten Aufgabe wurden Sie gebeten, Struts von http://jakarta.apache.org/struts/index.html herunterzuladen und Ihre eigene Struts-Action-Klasse zu implementieren.

Für diese Aufgabe habe ich mich entschieden, eine Struts-Action in Verbindung mit der JSP Standard Tag Library (JSTL) zu implementieren, um die Webanwendung von Beispiel 1 zu internationalisieren. Obwohl Struts die notwendige Infrastruktur für die Internationalisierung Ihrer Webanwendungen bietet, sollten Sie JSTL für diese Aufgabe verwenden, da JSTL ein Standard ist. Irgendwann werden die Internationalisierungsfunktionen von Struts wahrscheinlich veraltet sein oder in JSTL integriert werden.

Nachdem ich die Webanwendung von Beispiel 1 mit einer Struts-Aktion und JSTL internationalisiert habe, habe ich diese Anwendung für Chinesisch lokalisiert. Abbildung H1 zeigt das Ergebnis.

Anmerkung: Ich kenne kein einziges Wort Chinesisch, geschweige denn, wie man die Sprache schreibt, daher ist das Chinesisch in Abbildung H1 aus willkürlichen Unicode-Zeichenfolgen zusammengesetzt. Aber es sieht trotzdem cool aus.

Abbildung H1. Internationalisierung mit einer Struts-Aktion. Klicken Sie auf die Miniaturansicht, um das Bild in voller Größe zu sehen.

Beachten Sie, dass ich die href-Attribute im flags.jsp von Beispiel 12 als leere Strings angegeben habe, so dass der Servlet-Container die aktuelle JSP neu lädt, wenn Sie auf die Flaggen klicken. Daher besteht der erste Schritt zur Internationalisierung der Webanwendung darin, eine URL für diese Attribute anzugeben, wie in Beispiel H1:

Beispiel H1. flags.jsp

Die URL für jedes href-Attribut ist die gleiche: flags.do. An diese URL werden zwei Anforderungsparameter angehängt: einer für das Gebietsschema, das dem Flag entspricht, und ein weiterer, der den Pfad der aktuellen JSP darstellt. Den letzteren Anforderungsparameter erhalten Sie durch den Aufruf der Http.ServletRequest.getServletPath()-Methode.

Im Deployment Descriptor der Anwendung habe ich alle URLs, die auf .do enden, dem Struts-Action-Servlet zugeordnet, etwa so:

Beispiel H2. WEB-INF/web.xml (Auszug)

Hinweis: Weitere Informationen über Struts und das Struts-Action-Servlet finden Sie in meinem Artikel „Take Command of Your Software“ (JavaWorld, Juni 2002).

Als Nächstes habe ich den Pfad /flags auf die Struts-Action actions.FlagAction in der Struts-Konfigurationsdatei abgebildet, die in Beispiel H3 aufgeführt ist:

Beispiel H3. WEB-INF/struts-config.xml

Aufgrund dieser Zuordnung bewirkt die URL flags.do, dass das Struts-Action-Servlet die Methode actions.FlagAction.execute() aufruft; daher wird beim Klicken auf eine Flagge die Methode actions.FlagAction.execute() aufgerufen. Beispiel H4 listet die Klasse actions.FlagAction auf:

Beispiel H4. WEB-INF/classes/actions/FlagAction.java

Die actions.FlagAction.execute()-Methode erhält eine Referenz auf den locale-Anforderungsparameter und übergibt diesen Wert an die set()-Methode der JSTL Config-Klasse. Diese Methode speichert die Zeichenkette, die das Gebietsschema repräsentiert, in der FMT_LOCALEKonfigurationseinstellung, die JSTL zur Lokalisierung von Text und zur Formatierung von Zahlen, Währungen, Prozenten und Datumsangaben verwendet.

Nachdem ich nun ein Gebietsschema für JSTL-Internationalisierungsaktionen angegeben habe, gebe ich als Nächstes ein Ressourcenbündel im Bereitstellungsdeskriptor der Anwendung an, von dem ein Auszug in Beispiel H5 aufgeführt ist:

Beispiel H5. WEB-INF/web.xml (Auszug)

Der Basisname des Ressourcenbündels resources ist für den Parameter javax.servlet.jsp.jstl.fmt.localizationContext zur Kontextinitialisierung angegeben. Das bedeutet, dass JSTL nach einer Datei mit dem Namen resources_en.properties sucht, wenn das Gebietsschema auf britisches Englisch (en-GB) eingestellt ist, und nach resources_zh.properties, wenn das Gebietsschema auf Chinesisch (zh-ZH) eingestellt ist.

Nachdem ich nun ein Ressourcenbündel und ein Gebietsschema für die JSTL-Internationalisierungsaktionen angegeben habe, ändere ich als Nächstes die JSP-Dateien, um diese Aktionen zu verwenden, wie die Beispiele H6-H9 zeigen:

Beispiel H6. sidebar-links.jsp

Beispiel H7. header.jsp

Beispiel H8. content.jsp

Beispiel H9. footer.jsp

Die JSPs der Beispiele H6-H9 verwenden die JSTL-Aktion <fmt:message> zum Extrahieren von Unicode-Zeichenfolgen aus dem im Bereitstellungsdeskriptor angegebenen Ressourcenbündel. Die Beispiele H10 und H11 listen die Ressourcenbündel für Englisch bzw. Chinesisch auf:

Beispiel H10. WEB-INF/classes/resources_en.properties

Beispiel H11. WEB-INF/classes/resources_zh.properties

Email

In einer E-Mail an mich schrieb Joseph Friedman:

In „Decorate Your Java Code“ (JavaWorld, Dezember 2001) schreiben Sie:

„Das umschließende Objekt – bekannt als Dekorator – entspricht der Schnittstelle des Objekts, das es umschließt, so dass der Dekorator verwendet werden kann, als wäre er eine Instanz des Objekts, das er umschließt.“

Das Codebeispiel dekoriert jedoch FileReader mit einem LineNumberReader und ruft readLine() auf, das nicht in der FileReader-Schnittstelle enthalten ist; daher verwenden Sie LineNumberReader nicht transparent.

Beide, FileReader und LineNumberReader, entsprechen der Schnittstelle, die durch die Klasse Reader definiert ist, die sie beide erweitern. Die Idee ist, dass man den Dekorator an jede Methode übergeben kann, die einen Verweis auf eine Reader erwartet. Diese Methoden wissen nichts von den besonderen Fähigkeiten des Dekorators – in diesem Fall die Fähigkeit, Dateien zu lesen und Zeilennummern zu erzeugen.

Die Tatsache, dass der Dekorator (eine oder mehrere) Methoden besitzt, die dem dekorierten Objekt fehlen, verstößt in keiner Weise gegen die Absicht des Decorator-Musters; in der Tat ist das das zentrale Merkmal dieses Musters: Funktionalität zur Laufzeit zu einem Objekt hinzuzufügen, indem Objekte rekursiv dekoriert werden.

Wenn Sie sich Design Patterns Seite 173 ansehen, werden Sie folgendes sehen:

Decorator Unterklassen können Operationen für spezifische Funktionalität hinzufügen. Die ScrollTo-Operation von ScrollDecorator ermöglicht es beispielsweise anderen Objekten, die Schnittstelle zu scrollen, *wenn* sie wissen, dass sich ein ScrollDecorator-Objekt in der Schnittstelle befindet.

David Geary ist der Autor von Core JSTL Mastering the JSP Standard TagLibrary, das diesen Herbst von Prentice-Hall und Sun Microsystems Press veröffentlicht wird; Advanced JavaServer Pages (PrenticeHall, 2001; ISBN: 0130307041) und der Graphic Java-Serie (Sun Microsystems Press). David entwickelt seit 18 Jahren objektorientierte Software mit einer Vielzahl von objektorientierten Sprachen. Seit der Veröffentlichung des GOF-Design Patterns Buches im Jahr 1994 ist David ein aktiver Verfechter von Design Patterns und hat Design Patterns in Smalltalk, C++ und Java verwendet und implementiert. Seit 1997 arbeitet David Vollzeit als Autor und gelegentlicher Redner und Berater. David ist Mitglied der Expertengruppen, die die benutzerdefinierte JSP-Standard-Tag-Bibliothek und JavaServer Faces definieren, und er trägt zum Apache Struts JSP-Framework bei.

Erfahren Sie mehr über dieses Thema

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.