Heute möchte ich euch gerne das Observer Pattern aus der Familie der Behavioral Patterns vorstellen. Es ist, zumindest nach meiner Einschätzung, eines der wichtigsten und meist genutzten Patterns und gehört, wie ich finde, zum Grundwissen eines guten Programmierers dazu. Einige werden möglichweise sagen, dass es man es an sich so heute gar nicht mehr selbst schreiben braucht, grade in Zeiten von Java und .NET welche über delegates und/oder events verfügen. Recht habt ihr ! Jedoch finde ich es wichtig eine Technologie von Grund auf zu verstehen und somit biete ich hier einen kleinen Crashkurs für Einsteiger.
Zum aufwärmen ein kleines Anwendungsbeispiel:
Stellen wir uns vor wir sitzen in einer Zentrale und müssen den Standort von Zügen überwachen. Was wäre das für ein unglaublicher Aufwand ständig nachzufragen wo sich ein Zug gerade befindet nicht wahr ? Warum also den Spieß nicht einfach umdrehen ? Sollen mir die Züge doch einfach bescheid geben wenn sich ihre aktuelle Position verändert hat. Dazu müsste ich diesen lediglich bescheid sagen : “Hey gib mir absofort deine Position durch wenn sich diese verändert hat“. Das hat außerdem den Vorteil, dass wenn meine Kollegen ebenfalls die Position dieses Zuges abfragen möchten, sie diesen nur bescheid zu geben brauchen.
Wie aber sieht das ganze in Form eines Objektmodells aus ?
Nun das ist ganz einfach. Stellen sie sich selbst (sie sind ja der Angestellte in der Zentrale) einfach als ein Observer (Beobachter) vor der sich bei dem gewünschten Zug auch als ein solcher Anmeldet (Register). Der Zug ist in diesem Fall unser Subject welcher eine Liste von Observern (Sie und Ihre Kollegen) hält und sie alle im Falle einer Änderung benachrichtigt (Notify). Das ist im Grunde schon alles worauf das Observer Pattern basiert.
Basteln wir ein paar Klassen :
Zunächst bauen wir uns eine klasse welche sie selbst repräsentiert. Dazu implementieren wir das Interface ITrainMonitor welches alle von uns benötigten Methoden (nämlich Update()) bereit hält. Natürlich müssen wir die eigentliche Implementierung dieser Methode noch schreiben aber dazu später mehr.
Danach brauchen wir natürlich noch unser Subject welches wir überwachen möchten. Unser Train Object hat neben den Attributen wie z.B. Speed oder Position noch die für unsere Architektur wichtigen Methoden :
- Register(Observer) -> damit wir uns bei einem Zug für Benachrichtigungen anmelden können
- UnRegister(Observer) -> um uns von den Benachrichtigungen wieder abzumelden
- Notify() -> die wichtigste Methode, welche uns über Statusänderungen informiert
Schauen wir uns das ganze mal in UML an

Wir wissen was zu tun ist, also ran an den Code :
Hier die Implementierung unseres TrainMonitors
public class TrainMonitor : ITrainMonitor
{
private string _name;
// <summary>
// Defaultconstructor
// </summary>
//
<param name="name">Name of the monitorer</param>
public TrainMonitor( string name )
{
_name = name;
}
// <summary>
// Name of the Monitorer
// </summary>
public string Name
{
get { return _name; }
}
// <summary>
// Train has changed its state so update the Monitor too
// </summary>
//
<param name="train">Train that has changed state</param>
public void Update( Train train )
{
Console.WriteLine( "Monitor {0} was notified that {1} changed location to {2} \n", _name, train.Name, train.Location );
}
}
unser Train is wie folgt implementiert
public abstract class Train
{
private string _name;
private string _location;
private List<ITrainMonitor> _observers;
protected Train( string name )
{
_observers = new List<ITrainMonitor>();
_name = name;
}
//Register a new Observer
public void RegisterObserver( ITrainMonitor monitor )
{
_observers.Add( monitor );
}
//Unregister an Observer
public void UnRegisterObserver( ITrainMonitor monitor )
{
_observers.Remove( monitor );
}
//Notify all Observers about made changes
public void Notify()
{
foreach ( ITrainMonitor observer in _observers )
observer.Update( this );
}
//Location of a train , setting will call up an Update on all Observers
public string Location
{
get { return _location; }
set
{
_location = value;
Notify();
}
}
public string Name
{
get { return _name; }
}
}
Noch ein kleines Beispielszenario zum testen
public static void Main(string[] args)
{
// A sample scenario
PassengerTrain passTrain = new PassengerTrain( "ICE" );
GoodsTrain goodsTrain = new GoodsTrain( "Vegetables" );
TrainMonitor monitor1 = new TrainMonitor( "Peter" );
TrainMonitor monitor2 = new TrainMonitor( "Simon" );
passTrain.RegisterObserver( monitor1 );
passTrain.RegisterObserver( monitor2 );
goodsTrain.RegisterObserver( monitor2 );
passTrain.Location = "Cologne";
goodsTrain.Location = "Bonn";
passTrain.UnRegisterObserver( monitor2 );
passTrain.Location = "Hamburg";
goodsTrain.Location = "Frankfurt";
Console.Write("Press any key to continue . . . ");
Console.ReadKey( true );
}
Und diese Ausgabe erfolgt

Das war doch gar nicht so schwer oder ? Ihr könnt den gesamten Beispielcode natürlich auch aus meinem SVN Repository herunterladen und nach euren Wünschen abändern oder damit rumspielen. Das allgemeingültige UML Diagram zum Observer Pattern könnt ihr euch im folgenden nochmal genauer anschauen.
Quelle : http://de.wikipedia.org
Ich hoffe ich konnte euch das Observer Pattern der GoF etwas näher bringen.
Den kompletten Sourcecode findet ihr HIER nochmal
Deutsch
Englisch


Leave a Reply