13.6. Weitere Konzepte zur effektiven Anwendungsentwicklung

Bei der Entwicklung von Anwendungen trifft man häufig auf wiederkehrende Probleme für die es meist nicht nur eine Lösung gibt, sondern auch ein Design-Pattern. In diesem Abschnitt werden solche Lösungen die das metaframework mit Klassen bereits unterstützt erläutert. Diese sind nicht notwendig für das Verständnis des metaframeworks, aber sinnvoll für die Anwendungsentwicklung mit diesem.

13.6.1. Composite-Struktur bei Request Handlern

Blickt man auf Anwendungen oder Webanwendungen so fällt auf das diese meist gegliedert sind. Es gibt einen Header, ein Menü zur Navigation, häufig eine Sidebar, eine große Fläche für den eigentlichen Inhalt und eventuell einen Footer. Technisch betrachtet möchte man diese Dinge auch trennen, was in einem separaten Request Handler für jeden Bereich resultiert. Jeder Request Handler liefert dann ein Datentransferobjekt mit Daten für seinen Bereich.

Nun stellt sich die Frage wie diese Datentransferobjekte kombiniert und einem View zum Rendern übergeben werden können. Hierfür unterstützt das metaframework eine Composite-Struktur für Request Handler wie in Abbildung Figure 13-13 dargestellt ist.

Figure 13-13. Definition der Composite-Struktur von Request Handlern in UML

Der CompositeRequestHandler ist ebenfalls ein Request Handler und besitzt eine qualifizierte Assoziation zu RequestHandler, d.h. der Zugriff auf einen nestedRequestHandler ist nur durch einen Wert vom Typ String möglich.

Mit der Standardimplementierung CompositeRequestHandlerBase können Request Handler im Konstruktor übergeben werden (als assoziatives Array) sowie über die qualifizierte Assoziation eingefügt werden:

$this->nestedRequestHandler->insert('header', $this->serviceRegistry->getComponent('header.handler'));
$this->nestedRequestHandler->insert('footer', $this->serviceRegistry->getComponent('footer.handler'));

Hier werden von der Service Registry ein Header- und Footer Handler geholt und diese in die qualifizierte Assoziation eingefügt.

Die Implementierung der Methode handle delegiert das Request Processing einfach an alle Request Handler und kombiniert die Datentransferobjekte in einem, wobei der qualifier als Schlüssel genutzt wird - analog zu den Request Handlern.

$header = $compositeDto->header;
$footer = $compositeDto->footer;

Obiges Programmlisting zeigt den Zugriff auf die Daten der einzelnen Request Handler über das zurückgegebene Datentransferobjekt des Composite Request Handlers.

13.6.2. Delegate- und Decorator-Pattern bei Request Handlern

Häufig tritt bei der Entwicklung einer Anwendung auch der Fall auf, das man prinzipiell etwas wiederverwenden könnte, jedoch kleine Anpassungen notwendig sind. Da etwas ändern und etwas anderes hinzufügen. Solche Anwendungsfälle sind u.a. durch das Decorator-Pattern beschrieben, das vorhandene Funktionalität ausschmücken kann. Im metaframework wird das Decorator-Pattern kombiniert mit dem Delegate-Pattern durch eine spezielle Basisklasse für Request Handler unterstützt. In Abbildung Figure 13-14 ist das zugehörige UML Modell zu sehen.

Figure 13-14. UML Modell des Decorate Request Handlers

Im Konstruktor der Klasse DecorateRequestHandler ist zu erkennen das der Delegate-Teil optional ist - dieser wird ebenfalls durch den CompositeRequestHandler unterstützt. Die Methode handle ruft zuerst die Methode handle des dekorierten Request Handlers auf. Anschließend wird das erhaltene Datentransferobjekt mit den Datentransferobjekten der Delegate Request Handlern kombiniert, analog Abschnitt Section 13.6.1 . Zum Schluss wird die Methode decorate aufgerufen und das von dieser Methode erhaltene Datentransferobjekt als Rückgabewert der Methode handle genutzt.

Durch diesen Ablauf kann die Methode decorate alle Daten des Datentransferobjektes beliebig dekorieren. Ein weiterer Vorteil ist das nur eine loose Kopplung zur Schnittstelle RequestHandler existiert. Dadurch besteht die Möglichkeit zum Layering von Dekorierern, d.h. DecorateRequestHandler können wiederum dekoriert werden.

Eine Alternative kann allerdings die Verwendung der Vererbung sein. Hier muss genau definiert werden, was erreicht werden soll. Eine Vererbung hat eine viel stärkere Kopplung als das Decorator- oder Delegate Pattern, da bei den beiden Pattern nur eine Kopplung zur Schnittstelle RequestHandler existiert. Bei Vererbung besteht eine direkte Kopplung zum konkreten Typ, allerdings ist dadurch auch der Zugriff auf alle nicht privaten Member und Methoden möglich.

Als Beispiel kann eine einfache Webanwendung herangezogen werden. Das Layout einer Webanwendung ist meist komplett oder für größere Bereiche einer Webanwendung gewollt gleich, d.h. es gibt einen Header, Footer, Sidebar, etc. Der eigentliche Inhaltswechsel findet im Haupt-Anzeigebereich statt, wo der Inhalt von unterschiedlichen Request Handlern bereitgestellt wird. Die Inhaltsänderungen in den angliedernden Bereichen (Header, Footer, Sidebar, etc.) ist meist geringer. Für solch ein Szenario kann ein Composite Request Handler genutzt werden, der die Request Handler für die einzelnen Bereiche zusammenfasst. Die Request Handler der Haupt-Anzeigebereiche werden DecorateRequestHandler und dekorieren den Request des Composite Request Handler. Somit kann auf einfache Weise ein einheitliches Design einer Webanwendung erreicht werden.