am 6. Mai 2009
Nachdem ich es die letzte Zeit ein wenig schleifen lassen habe, was PHP im speziellen angeht, will ich mich heute mal wieder auf die Programmierung konzentrieren. Jetzt wo ich drüber nachdenke, ist es was allgemeines, was ich erklären will, ich es aber anhand von PHP erklären werde. Mann mann mann, wie kompliziert und dabei haben wir nicht mal angefangen.Wie auch immer, ich werde heute versuchen ein nettes Entwurfsmuster zu erläutern, dem Observer Pattern, was wohl im deutschen Beobachter-Muster heißt, aber den Namen vergessen wir schnell wieder.
Um die Motivation hoch zu halten mal schnell am Anfang die Idee, die hinter diesem Muster steckt. Prinzipiell geht es darum informiert zu werden, falls sich ein bestimmtes Objekt ändert, ohne dafür das Objekt anpassen zu müssen. Eigentlich ist es noch besser, das Objekt muss gar nicht wissen, dass es beobachtet wird. Wir müssen lediglich definieren über welche Änderungen wir die Aussenwelt informieren müssen und dann kann es schon losgehen. So jetzt noch ein Beispiel aus der Praxis, falls mir eins einfällt. Das doofe “Auto informiert bei über 120 km/h einen Piepser”-Beispiel kann man ja fast gar nicht mehr bringen. Und aus dem Grund nehmen wir es einfach … nur ein Witz. Stellen wir uns ein digitales Hühnchen im Ofen vor. Der Ofen will informiert werden, wenn das Hähnchen 150 Grad in der Mitte erreicht hat, um den Koch zu informieren (habe ich erwähnt, dass ich Hunger habe?). Ich werde glaube ich in die Geschichte eingehen, als der PHP Entwickler mit den miesesten Beispielen. Naja wenigstens ein neuer Superlativ.
So genug gelabert, jetzt wollen wir den Code sprechen lassen. Fangen wir also an:
class Chicken
{
}
class Oven
{
}
Wir fangen wirklich mit dem simplen Grundgerüst an. Zwei Klassen und kein “Schi-Schi”. Damit können wir zwar noch nichts anfangen, aber für den Anfang reicht es. Jetzt brauchen wir die Möglichkeit einen Observer dem Chicken hinzuzufügen. Das geht ganz einfach über die addObserver Methode, die wir jetzt schreiben werden.
class Chicken
{
private $observers = array( );
public function addObserver( Observer $observer )
{
$this->observers[] = $observer;
}
}
So, der Observer ist nun ganz einfach hinzugefügt. Der nächste Schritt ist das reagieren auf eine Veränderung. Wir müssen also alle Observer informieren, dass zum Beispiel die Temperatur des Gockels gestiegen ist. Das machen wir wie folgt:
class Chicken
{
private $observers = array( );
private $innerTemp = 30;
const OBSERVER_TEMPERATURE_INCREASED = 'ob_temp_inc';
public function getInnerTemperature( )
{
return $this->innerTemp;
}
public function addObserver( Observer $observer )
{
$this->observers[] = $observer;
}
public function increaseTemperature( $deltaTemp )
{
$this->innerTemp += $deltaTemp;
$this->notifyObservers( self::OBSERVER_TEMPERATURE_INCREASED );
}
private function notifyObservers( $notificationType )
{
foreach( $this->observers as $observer ) {
$observer->notify( $notificationType, $this );
}
}
}
Dadaaa, fertig. Unser Observer wird jetzt informiert, wenn die Temperatur erhöht wird. Und nicht nur unseren Observer, sondern alle, die wir hinzugefügt haben. $this geben wir auch noch mit, damit unser Observer auch was zum arbeiten hat. Unser konkreter Hühnchenfertig-Observer würde dann so ungefähr aussehen:
class ChickenObserver extends Observer
{
public function notify( $notificationType, $chicken )
{
if ( $chicken->getInnerTemparature( ) > 150 ) {
Alarm::ring( );
}
}
}
Eigentlich gibt es jetzt nichts mehr zu tun. Wie man den Observer dem Hühnchen hinzufügt, muss ich euch ja nicht mehr erklären. Vielleicht ist euch ja aufgefallen, dass das Hühnchen nicht weiss, dass es einen Ofen oder ähnliches gibt. Die Klasse muss sich also nur um das kümmern, was wirklich zu ihr gehört. Ich baue mir kein God-Objekt, das alles mögliche macht und auch bei jedem neuen Use-Case erweitert wird. Separation of Concerns ist hier auch wieder das Zauberwort. Wunderbar saubere Klassen sind die Folge und was will ein OOP Jünger lieber.
Die PHP Macher haben sich aber auch schon Gedanken über dieses Muster gemacht und es ging meiner Meinung nach an einer Stelle ziemlich in die Hose. In der SPL wird ein Interface für alles “Observable” definiert. Um einen Observer hinzuzufügen muss man hier die Methode “attach” verwenden. attachObserver wäre aber der eindeutig bessere Name, denn so kann ich die Methode attach gar nicht mehr verwenden, den Namen habe ich mir jetzt auf immer aus meinem Sortiment verbannt. Dabei ist attach so allgemein, dass ich es nicht ausschließen kann, dieses zu brauchen. Naja egal, ich hatte mich glaube ich schon mal darüber ausgelassen.
Ich hoffe, dass ich euch ein wenig die Eleganz des Entwurfsmuster ein wenig näher bringen konnte. Ich jedenfalls verwende es häufig und es hilft einen ungemein seine Klassen sauber zu halten und OOP strkt durchzuhalten.