Decorator-Pattern (Thema: PHP Beispiele)

Beispiel zur Implementierung des Decorator-Patterns in PHP

URL: http://www.rither.de/a/informatik/php-beispiele/klassen/decorator-pattern/

1. Über das Decorator-Pattern

Das Decorator-Pattern ist ein Muster für eine Möglichkeit, Klassen dynamisch und sehr flexibel in ihren Eigenschaften und Funktionen zu erweitern. Kernprinzip ist es, dass es ein oder mehr sogenannte "konkrete Komponenten" gibt, sowie ebenfalls ein oder mehr Dekorierer (Decorators). Die konkreten Komponenten werden durch die Dekorierer erweitert. Mehrere Dekorierer lassen sich kombinieren bzw. "stapeln".

Häufig genannt wird das Kaffee-Beispiel: Ein Laden verkauft Kaffee mit verschiedenen Ergänzungsmöglichkeiten, wie Sahne, Karamell, extra Milch oder extra Zucker. Abhängig von den Zusätzen variieren zum Beispiel Preis, Kalorien und Zubereitungszeit des Kaffees. Es soll jede erdenkliche Kombination möglich sein. Dem Decorator-Pattern folgend ist nun der Kaffee die konkrete Komponente, während Sahne, Karamell, extra Milch und extra Zucker die Dekorierer sind. Bei der Instanziierung eines Dekorierers wird entweder ein Kaffee-Objekt oder ein anderer Dekorierer an den Konstruktor übergeben. So ergeben sich Kombinationen der Art Sahne(Sahne(Karamell(Kaffee))) oder etwa ExtraMilch(ExtraZucker(Kaffee)).

Sowohl die Dekorierer als auch die konkrete Komponente implementieren das selbe Interface, wodurch auf die Dekorierer die gleichen Funktionen angewendet werden können wie auf die konkrete Komponente. Würde etwa bei der Kombination ExtraMilch(ExtraZucker(Kaffee)) vom äußersten Dekorierer die Methode getPrice() aufgerufen werden, dann könnte er „0,25€ + getPrice() vom dekorierten Objekt” zurückgeben. Entsprechend würde er den Dekorierer ExtraZucker aufrufen, der nach dem selben Prinzip 0,10€ hinzuaddiert und den Preis vom Kaffee abfragt.

2. Beispiel mit Strings

In diesem Beispiel wird das Decorator-Pattern auf das „Säubern” von Strings angewendet, die von Benutzern übergeben wurden. Zum Beispiel sollen überflüssige Leerzeichen entfernt und HTML codiert werden.

Es gibt eine konkrete Komponente „SanitizeableString”, welche dekoriert werden soll. Dazu stehen die Dekorierer TrimmedString, EncodeHtml und OnlyAtoZ zur Verfügung. Ersterer führt einen trim() auf den dekorierten String aus, EncodeHtml encodiert die HTML-Zeichen via htmlentities() und OnlyAtoZ entfernt alle Zeichen, die nicht im Bereich von a bis z liegen. So würde etwa die Kombination TrimmedString(EncodeHtml(EncodeHtml(SanitizeableString))) den String aus SanitizeableString zuerst doppelt encodieren und dann trimmen.

PHP-Code: Decorator-Pattern um Benutzereingaben zu filtern oder zu korrigieren
<?php
	// Interface, das sowohl die Dekorierer als auch die konkrete Komponente einbinden
	// So brauchen sich Klassen "außerhalb" dieses Decorator-Patterns nicht darum kümmern,
	// das es Dekorierer gibt, sondern rufen (hier) einfach getString() auf bzw. prüfen auf
	// das Interface ISanitizeable
	interface ISanitizeable {
		public function getString();
	}
	
	// Konkrete Komponente
	class SanitizeableString implements ISanitizeable {
		private $str;
		public function __construct($str) {
			$this->str = $str;
		}
		
		public function getString() {
			return $this->str;
		}
	}
	
	// Oberklasse aller Dekorierer
	abstract class SanitizedStringDecorator implements ISanitizeable {
		private $str;
		public function __construct(ISanitizeable $str) {
			$this->str = $str;
		}
		
		public function getString() {
			return $this->str->getString();
		}
	}
	
	// Dekorierer, der ein trim() auf den String ausführt
	class TrimmedString extends SanitizedStringDecorator {
		public function getString() {
			return trim(parent::getString());
		}
	}
	
	// Dekorierer, der HTML-Zeichen im String encoded
	class EncodeHtml extends SanitizedStringDecorator {
		public function getString() {
			return htmlentities(parent::getString(), ENT_QUOTES, 'UTF-8');
		}
	}
	
	// Dekorierer, der alle Zeichen entfernt, die nicht im Bereich a bis z liegen
	class OnlyAtoZ extends SanitizedStringDecorator {
		public function getString() {
			return preg_replace('/[^a-zA-Z]/', '', parent::getString());
		}
	}
	
	
	// Undekorierter String
	$str1 = new SanitizeableString('Ein Beispielsatz.');
	var_dump($str1->getString());
	
	// String mit trim()
	$str2 = new TrimmedString(new SanitizeableString('      Ein Beispielsatz.    '));
	var_dump($str2->getString());
	
	// String mit codierten HTML-Zeichen
	$str3 = new EncodeHtml(new SanitizeableString('   Das ist ein <b>Test!</b>   '));
	var_dump($str3->getString());
	
	// String mit codierten HTML-Zeichen, nur Zeichen aus dem Bereich a-z und trim()
	// aus "   <>   "
	// wird "   &lt;&gt;   " (EncodeHtml)
	// daraus wiederum "   ltgt   " (OnlyAtoZ)
	// und schließlich "ltgt" (TrimmedString)
	$str4 = new TrimmedString(new OnlyAtoZ(new EncodeHtml(new SanitizeableString('   <>   '))));
	var_dump($str4->getString());
?>

HTML-Code: Ausgabe
string(17) "Ein Beispielsatz."
string(17) "Ein Beispielsatz."
string(42) "   Das ist ein &lt;b&gt;Test!&lt;/b&gt;   "
string(4) "ltgt"


Um unsere Webseite für Sie optimal zu gestalten und fortlaufend verbessern zu können, verwenden wir Cookies. Durch die weitere Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen zu Cookies erhalten Sie in unserer Datenschutzerklärung. OK