Auf Kommentar antworten

Observer Pattern

Ein Observer dient dazu, den Zustand einer Klasse zu überwachen und bestimmte Maßnahmen einzuleiten, falls sich dieser verändert. Im Beispiel geht es darum einen Wert einer Klasse auf das Überschreiten eines Limits hin zu observieren und entsprechende Meldungen auszugeben.

Die Klasse Bar besitzt ein Attribut $_foo welches durch raiseFoo($value) um den übergebenen Wert $value erhöht werden kann.

Dieser Wert soll nun mit Hilfe des Observer Patterns auf das Überschreiten bestimmter Werte überwacht werden.

class BarClass {
 
  private $_foo = 0;
 
  public function raiseFoo($value) {
    $this->_foo += intval($value);
    echo 'Foo beträgt ',$this->_foo;
    $this->notify();
  }
 
  public function getFoo() {
    return $this->_foo;
  }
}

Die notwenidigen Interfaces für das Observer Pattern wurden für ein besseres Verständnis von Hand implementiert. Die in PHP5 verfügbare SPL-StandardPHPLibrary bietet diese Interfaces jedoch mit ähnlichem Naming bereits an. Ist also sichergestellt, dass die Applikation über diese verfügt, sollte auf die verfügbaren Interfaces SplSubject und SplObserver zurückgegriffen werden.

ObservableInterface

Interface für observierbare Klassen

interface ObservableInterface {
 
  // Add observer
  public function registerObserver(ObserverInterface $observer);
 
  // Delete observer
  public function unregisterObserver(ObserverInterface $observer);
 
  // Inform observer
  public function notify();
}

ObserverInterface

Interface für Observer

interface ObserverInterface {
 
  // Inform registered observers
  public function update(ObservableInterface $object);
}

BarClass

Die Klasse Bar implementiert nun das ObservableInterface und wurde um die Möglichkeiten Observer bei sich zu registrieren und diese ebenfalls wieder zu de-registrieren erweitert. Weiterhin werden über die Methode notify() alle registrierten Observer durch deren update() Methoden informiert, indem die Klasse "sich selbst übergibt" (SCNR ;-) ).

class BarClass implements ObservableInterface {
 
  /**
   * Storage for observers
   */
  private $_observers = array();
 
  private $_foo = 0;
 
  /**
   * Add observer
   */
  public function registerObserver(ObserverInterface $observer) {
    $this->_observers[] = $observer;
  }
 
  /**
   * Delete Observer
   */
  public function unregisterObserver(ObserverInterface $observer) {
    unset($this->_observers[array_search($observer,$this->_observers)]);
  }
 
  /**
   * Inform observers
   */
  public function notify() {
    foreach ($this->_observers as $observer) {
      $observer->update($this);
    }
  }
 
  public function raiseFoo($value) {
    $this->_foo += intval($value);
    echo 'Foo beträgt ',$this->_foo;
    $this->notify();
  }
 
  public function getFoo() {
    return $this->_foo;
  }
}

FooObserver

Ein Observer namens Foo, welcher die zu observierenden Klassen auf das Überschreiten eines bestimmten Attributs überwacht. Der Grenzwert $limit wird im Konstruktor übergeben. Sollte dieser im zu überwachenden Objekt überschritten werden, wird eine Meldung ausgegeben und der Observer de-registriert sich selbst beim Objekt um weitere Meldungen zu vermeiden.

class FooObserver implements ObserverInterface {
 
  private $_limit;
 
  public function __construct($limit) {
    $this->_limit = intval($limit);
  }
 
  public function update(ObservableInterface $object) {
    if ($object->getFoo() > $this->_limit) {
      echo 'Foo hat ',$this->_limit,' überschritten!';
      $object->unregisterObserver($this);
    }
  }
}

Und das ganze nun im Einsatz:

// Instanz auf zu observierende Klasse
$bar = new BarClass();
// Observer, welcher auf Limit 500 prüft
$bar->registerObserver(new Observer_FooObserver(500));
// Observer, welcher auf Limit 250 prüft
$bar->registerObserver(new Observer_FooObserver(250));
// Wert erhöhen
$bar->raiseFoo(200);
$bar->raiseFoo(100);
$bar->raiseFoo(100);
$bar->raiseFoo(200);

Bar wird instanziiert und mit zwei Observern versehen. Diese haben zwei verschiedene Limits (500,250) übergeben bekommen, auf welche die Klasse observiert werden soll.

Anschließend wird der Wert von $bar durch raiseFoo(..) mehrmals erhöht, um die beiden Limits zu übersteigen.

Ausgabe:

Foo 200
Foo 300
Foo hat 250 überschritten!
Foo 400
Foo 600
Foo hat 500 überschritten!

In der Ausgabe ist ersichtlich, dass beide Observer angeschlagen und die Überschreitung ihres Limits bemerkt und gemeldet haben. Da sich der Observer nach Festellung der Überschreitung selbstständig entfernt, wird vermieden, dass er bei jedem weiteren Aufruf von raiseFoo(..) eine Meldung ausgibt.

Antworten

Der Inhalt dieses Feldes wird nicht öffentlich zugänglich angezeigt.
  • Internet- und E-Mail-Adressen werden automatisch umgewandelt.
  • Zulässige HTML-Tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <abbr>
  • Zeilen und Absätze werden automatisch erzeugt.

Weitere Informationen über Formatierungsoptionen