Quicknavi |
|
Erweiterung bestehender Funktionen
1. Einführung
In der täglichen Arbeit tritt häufig die Situation auf, dass eine bestehende Bibliothek
die bisherigen Anforderungen erfüllt hat, der aktuell zu lösende Spezialfall jedoch nicht.
Viele Entwickler neigen in der geschilderten Situation dazu, die Funktion für den aktuellen
Anwendungsfall neu zu implementieren. Andere wiederum versuchen krampfhaft eine Bibliothek zu suchen,
die diesen Spezialfall abdeckt. Diese Möglichkeiten führt zwar sicher zum Ziel, verringern
jedoch entweder die Wartbarkeit, da weitere externe Bibliotheken eingebunden oder gar beliebig
kombiniert werden, und erhöhen dabei gleichzeit die Fehleranfälligkeit. Darüber hinaus
sollte sich jeder bewusst sein, dass eine API-Änderung automatisch bedeutet, sich vom
Update-Pfad der eingesetzten Bibliothek zu entfernen, da in einer Version eingefügte Quick-Hacks
womöglich in einer neueren Version nicht mehr funktionieren.
Dieses Tutorial möchte daher eine Methode aufzeigen, wie bestehende Funktionen ohne Anpassung
an der verwendeten Biblothek für den eigenen Bedarf "angepasst" und genutzt werden können.
Das Tutorial geht dabei davon aus, dass die behandelten Bibliotheken bzw. Module kein eigener Code
ist, da diese Methode sonst keinen Sinn macht.
Mancher Leser wird zurecht anmerken, dass eine Anpassung einer Bibliothek bedeutet, dass die Signatur
- die API der Bibliothek, oder des Moduls - nicht allgemeingültig genug ausgelegt ist. In vielen
Fällen muss ich dem Leser Recht geben, es gibt jedoch erfahrungsgemäß relativ viele
API-Definitionen, die nicht für exakt jeden Anwendungsfall mit genau einer Methode verwendbar
sind.
2. Beispiel einer TagLib
Das folgende Beispiel soll an Hand des im Release des Frameworks enthaltenen Moduls
socialbookmark zeigen, wie eine vorhandene Bibliothek für den eigenen Gebrauch
erweitert werden kann.
2.1. Aufgabenstellung
Die im adventure-codepack-* enthaltenen Bibliotheken des Moduls, sehen die
Möglichkeit vor, dieses per XML-Tag in den Inhaltsbereich einzubinden. Dazu enthält das Modul
eine TagLib, deren Eigenschaften unter Mitgelieferte Module,
Kapitel 5, beschrieben werden. Die Tagdefinition sieht dabei vor, dass ein Titel der aktuellen Seiten,
der beim Bookmarkservice als Linktitel verwendet wird, als Tag-Attribut übergeben werden kann.
Da die Definition jedoch statisch ist, ist es zunächst nicht möglich einen dynamischen Titel
an die TagLib zu übergeben. Gerade in einer CMS-Seite, in der der Titel abhängig der
anzuzeigenden Seite dynamisch variiert, ist das problematisch!
2.2. Analyse der bestehenden API
Um die aktuell mögliche Funktion zu analysieren, muss sich der Entwickler die Frage stellen:
"Was ist schon möglich und was fehlt wirklich?". Im Fall des
Socialbookmarking-Moduls ist die Antwort denkbar einfach: statisches Anzeigen der
Bookmark-Icons ist möglich, dynamische Titel nicht!
2.3. Erweiterung der API durch Wrapping
Ein sehr beliebtes Mittel ist Wrapping. Wrapping in der Programmierung
bedeutet, eine weitere Schicht um eine Bibliothek - oder hier eine Taglib - zu legen und dadurch die
Funktionalität ohne Veränderung der eingesetzten Komponente zu erweitern.
Betrachten wir zunächst die Funktionalität der bisherigen TagLib-Klasse. Diese implementiert
eine transform()-Methode, die die Tag-Eigenschaften an den socialbookmarkManager
übergibt und diesen für die Ausgabe der Bookmarking-Elemente verwendet. Der Quellcode der
Klasse (im adventure-codepack-* zu finden unter apps/modules/socialbookmark/pres/taglib)
wird im folgenden Kasten dargestellt (Kommentare wurden gekürzt):
class social_taglib_bookmark extends Document {
function social_taglib_bookmark(){ $this->__Attributes['width'] = '20'; $this->__Attributes['height'] = '20'; $this->__Attributes['title'] = null; $this->__Attributes['url'] = null; $this->__Attributes['target'] = null; // end function }
function transform(){
// Bookmark-Manager holen $sBM = &$this->__getServiceObject('modules::socialbookmark::biz','socialBookmarkManager');
// Breite und Höhe konfigurieren $sBM->set('Width',$this->__Attributes['width']); $sBM->set('Height',$this->__Attributes['height']);
// URL-Parameter konfigurieren if($this->__Attributes['url'] != null){ $sBM->set('URL',$this->__Attributes['url']); // end if } if($this->__Attributes['title'] != null){ $sBM->set('Title',$this->__Attributes['title']); // end if } if($this->__Attributes['target'] != null){ $sBM->set('Target',$this->__Attributes['target']); // end if }
// Bookmark-Quelltext zurückliefern return $sBM->getBookmarkCode();
// end function }
// end class }
Um den Titel der aktuell angezeigten Seite dynamisch zu gestalten, ist es nun ratsam, eine weitere
TagLib zu definieren, die ausschließlich die neue Funktionalität beinhaltet, jedoch Gebrauch
der bereits bestehenden Funktion macht. Um ein konkretes Beispiel aufzeigen zu können, soll der
neu zu erstellende Tag my:bookmark genannt werden. Wie im Tutorial
TagLibs erstellen beschrieben,
ergibt sich dadurch der Klassenname my_taglib_bookmark. Diese beinhaltet dann
folgenden Quellcode:
import('modules::socialbookmark::pres::taglib','social_taglib_bookmark');
class my_taglib_bookmark extends social_taglib_bookmark {
function my_taglib_bookmark(){ // Ausfuehren des Konstruktors der Eltern-Klasse parent::social_taglib_bookmark(); // end function }
function transform(){
// Beziehen des aktuellen Titels $Title = /* Aktueller Titel */;
// Title in Tag-Attribut einsetzen $this->__Attributes['title'] = $Title;
// Ausgabe mit Hilfe der Eltern-Methode transform() erzeugen return parent::transform();
// end function }
// end class }
In der Methode transform() wird dabei lediglich der Titel der Seite je nach
Anwendungsfall erzeugt und dem dafür vorgesehenen Attribut übergeben. Die eigentliche
Erzeugung der Ausgabe wird der bisherigen TagLib-Methode überlassen. Durch diese Änderung
bleibt es weiterhin möglich, dem Tag die Attribute
mitzugeben, ohne das Verhalten nochmals in der neuen Klasse implementieren zu müssen. Das
Einbinden der erweiterten TagLib funktioniert dann wie gewohnt mit
<core:addtaglib namespace="dein::namespace" prefix="my" class="bookmark" />
<my:bookmark width="16" height="16" target="_blank" />
2.4. Umgang mit Updates
Sollte die verwendete Bibliothek zukünftig eine andere API unterstützen, beschränkt
sich die Anpassung lediglich auf das Füllen des Attributes title, da der interne
Ablauf der Methode transform() unberührt bleibt. Weiterer Vorteil ist, dass die
API der Wrapper-Klasse konstant bleibt und keine Anpassung im Gesamtsystem zur Einbindung des Moduls
vorgenommen werden muss. Das in diesem Tutorial aufgezeigte Beispiel hat sich zwar "nur" auf die
Erweiterung einer TagLib beschränkt, das Prinzip ist jedoch auf andere Bereiche anwendbar.
Kommentare
Möchten Sie den Artikel eine Anmerkung hinzufügen, oder haben Sie ergänzende Hinweise? Dann können Sie diese hier einfügen. Die bereits verfassten Anmerkungen und Kommentare finden Sie in der untenstehenden Liste.
Für diesen Artikel liegen aktuell keine Kommentare vor.
|