Inhaltsverzeichnis
Einführung
Fortlaufendes Beispiel
Als fortlaufendes, "wissenschaftliches" Beispiel wird hier für den Informatiker eine kleine Welt geschaffen, in dem er sich wohlfühlen und austoben kann. In diesem Beispiel werden die aufgeführten Entwurfsmuster in einem anschaulichen Zusammenhang verwendet.
Letzte Änderung: 14.05.2009 16:41 Uhr
Singleton
Erläuterung
Bei dem Singleton-Entwurfsmuster handelt es sich um ein erzeugendes Muster. Hierbei wird dafür gesorgt, dass nur eine Instanz einer Klasse existieren kann. Um dies zu erreichen werden Konstruktor und Methoden zum Klonen als
private oder
protected gekennzeichnet. Die Instanziierung der Klasse erfolgt durch einen Methodenaufruf. Allgemein wird als Methodenname
singleton oder
getInstance verwendet.
UML
[...]
PHP-Implementierung
PHP:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <?php
class EinfacheSingletonKlasse {
static private $_instance;
protected function __construct() {
}
protected function __clone() {
}
static public function singleton() {
if (! self::$_instance instanceof self) {
self::$_instance = new self();
}
return self::$_instance;
}
} |
Fortlaufendes Beispiel
Basis der Informatikerwelt bildet ein Gott. Wie allgemein bekannt gibt es genau einen Gott, wodurch sich für Ihn das Singleton-Pattern anbietet. Eine einfache Implementierung von Gott könnte also so (oder ähnlich) aussehen:
PHP:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| <?php
class God {
static private $_instance;
protected function __construct() {
}
protected function __clone() {
}
static public function singleton() {
if (! self::$_instance instanceof self) {
self::$_instance = new self();
}
return self::$_instance;
}
public function isAlmighty() {
return true;
}
} |
Letzte Änderung: 14.05.2009 16:40 Uhr
Factory
Erläuterung
Die Abstract-Factory ist ein erzeugendes Entwurfsmuster. Hier wird mit Hilfe von zwei abstrakten Klassen sowohl ein Produkt als auch eine Fabrik abgebildet, die anschließend als konkrete Fabrik oder konkretes Produkt implementiert werden. Durch Aufruf einer Methode innerhalb der Fabrik werden neue Instanzen der Produkt-Klasse erzeugt und zurückgegeben. Eine Abstract-Factory hat also gewisse Ähnlichkeit mit anderen erzeugenden Entwurfsmustern, wie beispielsweise dem
Singleton-Pattern.
UML
[...]
PHP-Implementierung
PHP:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <?php
abstract class Product() {
}
class MyProduct extends Product() {
}
abstract class Factory {
abstract public function createProduct();
}
class MyFactory extends Factory {
public function createProduct() {
return new MyProduct();
}
} |
Fortlaufendes Beispiel
Das wichtigste Produkt für den Informatiker ist natürlich der Kaffee. Entsprechend gibt es eine beliebige Anzahl an Replikatoren, die eine Tasse Kaffe erzeugen und ausgeben können.
Zunächst werden also die Abstrakten Klassen der Abstract Factory erstellt.
PHP:1
2
3
4
5
| <?php
abstract class Product {
} |
PHP:1
2
3
4
5
6
| <?php
abstract class Factory {
} |
Diese werden nun als Produkt und reale Factory-Implementierung abgebildet. Für spätere Zwecke erhält das Produkt einige zusätzliche Methoden zum leeren des Füllstandes und zum Prüfen, ob es leer ist.
PHP:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <?php
require_once 'product.php';
class CupOfCoffee extends Product {
private $_fillingLevel = 1;
public function __construct() {
}
public function reduceFillingLevel() {
if (! $this->isEmpty()) {
$this->_fillingLevel = $this->_fillinglevel - 0.2;
} else {
throw new Exception('The cup is empty');
}
}
public function isEmpty() {
return $this->_fillingLevel <= 0;
}
} |
Abschließend wird nun die Replikatorklasse erstellt. Dieser Replikator kann nur neue Kaffeetassen erzeugen.
PHP:1
2
3
4
5
6
7
8
9
10
11
12
| <?php
require_once 'factory.php';
require_once 'cupofcoffee.php';
class Replikator extends Factory {
public function createCupOfCoffee() {
return new CupOfCoffee();
}
} |
Die Verwendung ist denkbar einfach. Es wird die Instanz eines Replikators erzeugt und auf diesem bei Bedarf Methoden zur Erzeugung von Produkten aufgerufen. Die entsprechende Methode gibt nun ein Produkt zurück, das wie gewohnt verwendet werden kann.
PHP:1
2
3
4
5
6
7
8
9
10
11
| <?php
require_once 'replicator.php';
$replicator = new Replicator();
$cup = $replicator->createCupOfCoffee();
try {
$cup->reduceFillingLevel();
} catch(Exception $e) {
echo $e->getMessage();
} |
Letzte Änderung: 14.05.2009 17:29 Uhr
Prototype
[Noch kein Text vorhanden]
Adapter
Ziel dieses Musters ist eine eigene Schnittstelle zu einer bereits vorhandenen Schnittstelle zu erstellen,
wenn die ursprüngliche Schnittstelle nicht kompatibel war.
ursprüngliche Schnittstelle
php:1
2
3
4
5
6
7
8
9
10
|
<?php
class wirbelsaeulentier {
public function open_maul(){}
public function close_maul(){}
public function kauen($things){}
public function schnlucken(){}
}
?> |
unsere Schnittstelle braucht aber folgende Methode
php:1
2
3
4
5
| <?php
class wirbelsaeulentier {
public function eat($things){}
}
?> |
Somit kommt das Adapter-Pattern zur Anwendung
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <?php
class wirbelsaeulentierAdapter(){
protected $wirbelsaeulentier = NULL;
public function __construct($wirbelsaeulentier){
$this->wirbelsaeulentier = $wirbelsaeulentier;
}
public function eat($things){
try{
$this->wirbelsaeulentier->open_maul();
$this->wirbelsaeulentier->kauen($things);
$this->wirbelsaeulentier->schlucken();
$this->wirbelsaeulentier->close_maul();
}catch(FrameworkException $e){
return false;
}
return true;
}
}
?> |
Letzte Änderung: 13.05.2009 20:22 Uhr
Bridge
[Noch kein Text vorhanden]
Composite
Eine Webanwendung besteht meistens aus mehreren Klassen. Wenn aber nicht jede Klasse nach außen sichtbar sein soll (information hidding), wird das Kompositum angewendet. Bei diesem Muster werden mehrere Objekte zu einem Objekt zusammen gefasst.
PHP Implementierung
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <?php
class LebewesenComposite{
protected $Lebewesen = array();
public function addLebewesen(Lebewesen_interface $Lebewesen){
$this->Lebewesen[] = $Lebewesen;
}
public function eat($things){
foreach ($this->Lebewesen as $Lebewesen_item){
$Lebewesen_item->eat($things);
}
}
public function drink($liter){
foreach ($this->Lebewesen as $Lebewesen_item){
$Lebewesen_item->drink($liter);
}
}
}
?> |
Interface
php:1
2
3
4
5
6
7
8
| <?php
interface Lebewesen_interface{
public function eat($things);
public function drink($liter);
}
?> |
komplette Anwendung
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| <?php
class wirbelsaeulentier implements Lebewesen_interface{
public function eat($things){}
public function drink($liter){
if($liter < 3){
}
}
}
class weichtier implements{
public function eat($things){}
public function drink($liter){
if($liter > 0.001){
}
}
}
$stier = new wirbelsaeulentier();
$mensch = new wirbelsaeulentier();
$regenwurm = new weichtier();
$welt = new LebewesenComposite();
$welt->addLebewesen($stier);
$welt->addLebewesen($mensch);
$welt->addLebewesen($regenwurm);
?> |
Letzte Änderung: 13.05.2009 20:23 Uhr
Decorator
Bestehende Klassen können nicht mehr durch extends zur Laufzeit erweitert werden. Mit dem Dekorierer ist dies nun möglich.
php:1
2
3
4
5
6
7
8
9
10
11
12
| <?php
class sprinter{
protected $max_speed;
public function __construct($speed = 100){
$this->max_speed = $speed;
}
public function get_max_speed(){
return $this->max_speed;
}
}
?> |
Was aber nun, wenn dem Sprinter Spikes zur Verfügung stehen?
php:1
2
3
4
5
| <?php
interface ausruestung{
public function get_additionalspeed();
}
?> |
php:1
2
3
4
5
6
7
| <?php
class spikes implements ausruestung{
public function get_additionalspeed(){
return 10;
}
}
?> |
Jetzt müssen wir nur noch die vorhande Klasse überarbeiten.
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <?php
class sprinter{
protected $max_speed;
protected $extra = array();
public function __construct($speed = 100){
$this->max_speed = $speed;
}
public function get_max_speed(){
$speed = $this->max_speed
foreach($this->extra as $extra){
$speed = $speed + $extra->get_additionalspeed();
}
return $speed;
}
public function addExtra(ausruestung $extra){
$this->extra[] = $extra;
}
}
?> |
Nun schauen wir mal wie schnell unserer Läufer ist:
php:1
2
3
4
5
6
7
8
| <?php
$alfred = new sprinter();
echo "Alfred hat keine Spikes an und läuft so schnell: ".$alfred->get_max_speed()."<br/>";
echo "Alfred zieht seine Spikes nun an..."."<br/>";
$spikes = new spikes();
$alfred->addExtra($spikes);
echo "Alfred hat nun Spikes an und läuft so schnell: ".$alfred->get_max_speed()."<br/>";
?> |
Ausgabe:
diff:1
2
3
4
|
Alfred hat keine Spikes an und läuft so schnell: 100
Alfred zieht seine Spikes nun an...
Alfred hat nun Spikes an und läuft so schnell: 110 |
Jetzt lassen wir ihn noch richtige Sprinterkleidung anziehen:
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <?php
class spikes implements ausruestung{
public function get_additionalspeed(){
return 10;
}
}
class hose implements ausruestung{
public function get_additionalspeed(){
return 2;
}
}
$alfred = new sprinter();
echo "Alfred hat keine Spikes an und läuft so schnell: ".$alfred->get_max_speed()."<br/>";
echo "Alfred zieht seine Spikes nun an..."."<br/>";
$spikes = new spikes();
$alfred->addExtra($spikes);
echo "Alfred hat nun Spikes an und läuft so schnell: ".$alfred->get_max_speed()."<br/>";
echo "Alfred zieht seine Sprinterkleidung nun an..."."<br/>";
$hose = new hose();
$alfred->addExtra($hose);
echo "Alfred hat nun eine andere Hose an und läuft so schnell: ".$alfred->get_max_speed()."<br/>";
?> |
Letzte Änderung: 14.05.2009 12:43 Uhr
Proxy
Dieses Muster erzeugt einen Stellvertreter für ein Objekt um den Zugriff zu überwachen.
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <?php
class sprinter implements Lebewesen_interface{
protected $max_speed;
protected $extra = array();
public function __construct($speed = 100){
$this->max_speed = $speed;
}
public function get_max_speed(){
$speed = $this->max_speed
foreach($this->extra as $extra){
$speed = $speed + $extra->get_additionalspeed();
}
return $speed;
}
public function addExtra(ausruestung $extra){
$this->extra[] = $extra;
}
public function eat($things){}
public function drink($liter){}
}
?> |
Jetzt wollen wir wissen, ob unser Alfred als Sportler dopt.
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| <?php
class sprinter_proxy implements Lebewesen_interface{
protected $max_speed = 100;
protected $extra = array();
public function __construct($original){
$this->instance = $original;
}
public function get_max_speed(){
return $this->instance->get_max_speed();
}
public function addExtra(ausruestung $extra){
return $this->instance->addExtra(ausruestung $extra);
}
public function eat($things){
if($things == "Doping"){
throw new Dopingexception("Sportler nimmt Dopingmittel.");
}else{
return $this->instance->eat($things);
}
}
public function drink($liter){
return $this->instance->drink($liter);
}
}
?> |
komplette Anwendung:
php:1
2
3
4
5
6
7
8
9
10
11
|
<?php
$alfred = new sprinter();
$alfred->eat('Doping');
$alfred_p = new sprinter_proxy($alfred);
$alfred_p->eat('Doping');
?> |
Letzte Änderung: 14.05.2009 12:41 Uhr
Facade
[Noch kein Text vorhanden]
Chain of Responsibility
[Noch kein Text vorhanden]
Iterator
Elemente eines Objektes können durch dieses Muster sequenziell angesprochen werden.
PHP(Version 5) bringt standardmäßig schon eine Implementierung dieses Musters mit:
Interface vom Iterator-Pattern:
php:1
2
3
4
5
6
7
8
9
10
11
| <?php
interface Iterator{
public function key();
public function next();
public function rewind();
public function valid();
public function current();
}
?> |
Jetzt wollen wir ein ganzes Startfeld von Sprinter darstellen.
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <?php
class startfeld{
private $sprinter = array();
public function __construct($csv){
}
public function countSprinter(){
return count($this->sprinter);
}
public function getSprinter($pos){
if($pos>=$this->countSprinter()){
}else{
return $this->sprinter[$pos];
}
}
}
?> |
Um das Startfeld auszugeben würde folgender Code verwendet:<br />
php:1
2
3
4
5
6
7
8
| <?php
$teilnehmer = new startfeld("export.csv");
for($i=0; $i < $teilnehmer->counterSprinter();$i++){
$sprinter = $teilnehmer->getSprinter($i);
echo $sprinter->getName();
}
?> |
Jetzt kommt das Pattern zum Einsatzt
php:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| <?php
class startfeld implements Iterator{
private $sprinter = array();
private $pos = 0;
public function __construct($csv){
}
public function countSprinter(){
return count($this->sprinter);
}
public function getSprinter($pos){
if($pos>=$this->countSprinter()){
}else{
return $this->sprinter[$pos];
}
}
public function key(){
return $this->pos;
}
public function next(){
$this->pos++;
}
public function rewind(){
$this->pos = 0;
}
public function valid(){
if($this->pos < $this->countSprinter()){
return true;
}
return false;
}
public function current(){
return $this->sprinter[$pos];
}
}
?> |
Somit kann die Ausgabe so geschrieben werden, dass dieselbige nur Methoden verwendet, die vom Iteratorpatter vorausgesetzt werden.
php:1
2
3
4
5
6
7
8
9
10
| <?php
$teilnehmer = new startfeld("export.csv");
while($teilnehmer->valid()){
$pos = $teilnehmer->key();
$sprinter = $teilnehmer->current();
echo "Sprinter mit der Nummer {$pos} heißt {$sprinter->getName()}";
$teilnehmer->next();
}
?> |
Oder mit Foreach:
php:1
2
3
4
5
6
| <?php
$teilnehmer = new startfeld("export.csv");
foreach($teilnehmer as $i => $sprinter){
echo "Sprinter mit der Nummer {$pos} heißt {$sprinter->getName()}";
}
?> |
Letzte Änderung: 13.05.2009 20:25 Uhr
Observer
Die genau Bezeichnung sollte Subject/Observer heißen. Ein Subjekt (subject) besitzt viele Abhängigkeiten(Verbindungen) zu beliebig vielen externen Beobachtern. Diese werden bei Zustandsänderungen des Subjektes informiert.
Letzte Änderung: 13.05.2009 20:26 Uhr
Visitor
[Noch kein Text vorhanden]
Plugin
[Noch kein Text vorhanden]
Inversion of Control
[Noch kein Text vorhanden]
Active-Record
Ähnelt sehr stark dem Row Data Gateway Pattern. Genau genommen beinhaltet es dieses, fügt aber noch weitere Logik dem Objekt hinzu.
Letzte Änderung: 13.05.2009 20:26 Uhr
Row Data Gateway
Dieses Pattern wird als Repräsentation einer Zeile von einer Datenbanktablle verwendet. Eine Instanz beschreibt eine Zeile. Mit Propel kann man solche Klassen automatisch erzeugen.
Letzte Änderung: 13.05.2009 20:26 Uhr
Statemachine
[Noch kein Text vorhanden]
MVC
Dieses Pattern ist genau genommen ein Zusammenschluss mehrerer Muster. Mit dem MVC können Schichten in einer Webanwendung getrennt werden.
Die Abkürzung steht für.
- Model: speichert Daten und kann dem View über Datenänderungen informieren
- View: stellt Daten dar und kann Daten beim Model abfragen
- Controller: nimmt Interaktionen mit dem Besucher auf und gibt Anweisungen an Model und View weiter.
Letzte Änderung: 31.05.2009 21:57 Uhr
HMVC
[Noch kein Text vorhanden]
PAC
[Noch kein Text vorhanden]
Diskussion