• PHP Entwurfsmuster: Decorator

    von Nils Langner 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.

    1. Ein Auto, das weder Spoiler noch verbesserte Bremsscheiben kennt
    2. Ein Auto, das einen Spoiler besitzt, aber keine neuen Bremsscheiben
    3. Ein Auto, das Bremsscheiben besitzt, aber keinen Spoiler
    4. 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.

    Nils Langner Nils Langner

    Auch wenn Ihr es mir nicht glauben werdet, aber ich habe nichts gegen PHP. Ich rege mich einfach nur gerne auf. Ok so schlimm ist es auch nicht. Eigentlich wollte ich schon immer einen Blog haben und da ...

    Zum Profil von Nils Langner

    1 Kommentar »


    • Malte
      am 9. Dezember 2008 um 22:32 Uhr

      was würde christian schmidt nur empfehlen? aber du schreibst es ja am ende des artikels.

      dabei wäre noch drauf hinzuweisen, das es sich um ein standardwerk der php entwicklung handelt und die deutschsprachige ausgabe nächstes jahr bei o’reilly in die zweite runde geht.

      unbedingt lesen, egal ob man mit zend framework oder etwas anderem arbeitet.

    RSS-Feed für Kommentare zu diesem Artikel. TrackBack-URL

    Einen Kommentar hinterlassen

    Werbung
    PHP Magazin
    Ausgabe 02/2010

    Dieses Mal mit Artikeln zu den Themen OpenSocial und Apache Shindig, Graphentheorie, Smarty3

    t3n
    Ausgabe 19

    Social Media (R)evolution. Weitere Themen sind noSQL, Crowdsourcing ...

    PHP Journal
    Ausgabe 2/2010

    PHP & Windows optimal nutzen, die besten PHP-CMS im Überblick, Google-API mit Zend Framework nutzen.

    Wir wurden schon öfters gefragt, ob man uns nicht irgendwie unterstützen kann. Die Antwort war immer einfach: Klar! Am einfachsten ist es eure nächsten Einkäufe bei Amazon über unsere Link abzuwickeln. Damit würdet ihr uns schon sehr helfen. Über Co-Autoren freuen wir uns aber noch mehr.