am 9. August 2008
In meinem allerersten Posting hatte ich ja bereits groß rum getönt, dass ich auf Themen aus der Softwaretechnik eingehen will. Heute ist es endlich soweit, denn mir ist ein schönes Beispiel für das Entwurfsmuster Dekorierer eingefallen. Bei der Definition habe ich einfach mal den Text aus der Wikipedia Vgenommen.
Der Decorator (auch Dekorierer) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung und gehört zur Kategorie der Strukturmuster (Structural Patterns). Das Muster ist eine flexible Alternative zur Unterklassenbildung, um eine Klasse um zusätzliche Funktionalitäten zu erweitern. Es ist ein Entwurfsmuster der sogenannten GoF-Muster (siehe Viererbande).
Wir verwenden das Muster also um Klassen zu erweitern. Aber warum kann man dies nicht einfach über Vererbung bewerkstelligen? Ganz einfach, manchmal will man auch eine Klasse zur Laufzeit erweitern und in diesem Fall kann dieses Pattern helfen. Ein weiterer Vorteil wird einem durch eine einfache Problemstellung klar, die man nicht einfach durch Vererbung lösen kann.
Stellen Sie sich vor, Sie müssen ein Auto als Objekt abbilden – ja ich weiß, die doofen Auto Beispiele, aber später werde ich Probleme vorstellen die aus meinem Arbeitsumfeld kommen. Dieses Auto soll also um zwei Features erweitert werden, das erste Feature ist ein Spoiler, der das Auto um 10 km/h schneller macht. Das zweite sind Bremsscheiben, die den maximale Bremsweg halbieren. Jetzt benötigen Sie Instanzen von vier Autos.
- Ein Auto, das weder Spoiler noch verbesserte Bremsscheiben kennt
- Ein Auto, das einen Spoiler besitzt, aber keine neuen Bremsscheiben
- Ein Auto, das Bremsscheiben besitzt, aber keinen Spoiler
- Ein Auto, das Bremsscheiben und Spoiler besitzt
Klingt eigentlich ganz einfach, aber wenn man sich mal genau Gedanken drüber macht, ist es nicht so trivial, wie es im ersten Augenblick den Eindruck macht. Und leider mussten wir auch bei unseren Assessmentcentern die Erfahrung machen, dass viele Bewerber dieses Problem nicht lösen konnten. Delegation über einen Dekorierer wäre hier das Zauberwort gewesen.
Aber gehen wir doch einfach zu einem Beispiel, dass mir die letzten Tage untergekommen ist. Es ging darum eine einfache Collection zu entwerfen. Diese Sammlung soll einfach als Container für alle möglichen Objekte dienen. Als Vorbild haben wir uns dafür das Collection Interface von Java geschnappt und es nachimplementiert. Ich hab jetzt mal das minimal Set dieses Interfaces angegeben. Es fehlen zwar ein paar Funktionen aber für die Erläuterung dieses Entwurfsmuster sollte es ausreichen.
interface iCollecton extends Iterator, Countable
{
public function add( $element );
public function remove ( $element );
}
Gegen dieses Interface sollen nun diverse Klassen implementiert werden. Set, HashMap und List wäre hier nur drei einfache Beispiele. Jetzt mussten diese Container in zwei verschiedenen Varianten existieren. Die erste Variante sollte alle möglichen Elemente entgegennehmen können. Die Zweite sollte typsicher sein, sie sollte nur Elemente von einem bestimmten Typ annehmen, der im Konstruktor definiert wurde. Über Ableitung kann dies leider nicht bewerkstelligt werden, ohne Code zu duplizieren. Über den Dekorierer ist dies aber kein Problem.
class TypeSaveCollectionDecorator implements iCollection
{
private $collection;
private $type;
public function __construct( iCollection $collection, $type )
{
$this->collcetion = $collection;
$this->type = $type;
}
public function add( $element )
{
if ( ! ( $element instanceof $this->type ) ) {
throw new Exception( 'Wrong type' );
}
return $this->collection->add( $element );
}
public function remove( $element )
{
return $this->collection->remove( $element );
}
}
Sieht eigentlich ganz einfach aus. Und das beste daran ist: es ist auch einfach! Wenn man sich mal mit diesem Muster beschäftigt hat, dann will man es nicht wieder missen. Der Aufruf des Decorators ist jetzt auch ganz einfach.
$parkingLot = new TypeSaveCollectionDecorator( new Set( ), 'iCar' );
Vielleicht konnte ja dieser tipp dem einen oder anderen helfen. Wie immer bei Design Pattern Fragen, kann ich nur das Buch der Gang of four empfehlen. Wer speziell an der PHP Implementierung interessiert ist, der sollte sich das Buch von Stefan Schmidt “PHP Design Pattern” mal genauer ansehen.
Zum Schluss sei noch erwähnt, dass ich der Einfachheit halber alle Funktionen des Countable und der Iterator Interfaces weggelassen habe.