Observer

Z PHPEdia.pl
Skocz do: nawigacji, wyszukiwania

Charakterystyka

Obserwator to wzorzec projektowy, umożliwiający stworzenie między obiektami zależności jeden-do-wielu. Zależność ta ma na celu automatyczne informowanie wielu obiektów o jakiejś zmianie stanu lub jakimś zdarzeniu.

Założenia

Wzorzec pozwala na:

  • jednolite traktowanie obserwatorów (wykorzystanie interfejsów),
  • dodawanie nowych obserwatorów bez konieczności modyfikacji istniejących klas,
  • zawiadamianie tylko zarejestrowanych obserwatorów,
  • obserwatorzy sami odpowiadają za rejestrowanie się u danego obiektu, co zapobiega wprowadzaniu zmian w obiekcie obserwowanym, a jednocześnie pozwala na zachowanie spójności.

Przykładowe implementacje

przykładowy kod dla PHP 5:

Aby zachować zgodność kodu z PHP 5.1 (gdzie interfejsy odpowiedzialne za wzorzec Obserwatora są domyślnie zdefiniowane w SPL), które obecnie nie jest w wersji ostatecznej, dla wersji 5.0.x definiujemy interfejsy Subject i Observer:

<?php
// jeśli wersja PHP < 5.1
 
// dla obiektu obserwowanego
interface Subject {
    public function attach(Observer $observer);
    public function detach(Observer $observer);
    public function notify();
}
 
// dla obserwatora
interface Observer {
    public function update(Subject $subject);
}
?>

W celu zmniejszenia ilości kodu(dla wygody) możemy zdefiniować abstrakcyjną klasą do dziedziczenia:

<?php
abstract class aSubject {
 
    /**
     * Tablica referencji do obserwatorów
     *
     * @var array
     * @access protected
     */
    protected $observers = array();
 
    /**
     * Rejestruje obserwatora, w celu późniejszego powiadomienia
     *
     * @param Observer Obserwator do zarejestrowania
     * @return void
     * @access public
     */
    public function attach(Observer $observer) {
        // obiekt obserwowany nie musi wiedzieć, jaki dokładnie
        // rodzaj obserwatora się u niego rejestruje
        // wystarczy, ze implementuje odpowiedni interfejs
        $this->observers[] = $observer;
    }
 
    /**
     * Wyrejestrowuje obserwatora
     *
     * @param Observer Obserwator do wyrejestrowania
     * @return void
     * @access public
     */
    public function detach(Observer $observer) {
        foreach($this->observers as &$value) {
            if($value === $observer) {
                // usuwamy tylko i wyśćcznie referencję!
                unset($value);
            }
        }
    }
 
    /**
     * Powiadamia obserwatorów o ewentualnych zmianach/zdarzeniach
     *
     * @return void
     * @access public
     */
    public function notify() {
        foreach($this->observers as $value) {
            $value->update($this);
        }
    }
 
}
?>

Przykładowe klasy wykorzystujące wzorzec:

<?php
class ExampleObservable extends aSubject implements Subject {
 
    /**
     * przykładowa właściwość - po prostu liczba
     *
     * @var integer
     * @access private
     */
    private $int;
 
    /**
     * przykładowa metoda
     * Ustawia nową wartość dla $this->int, informuje o tym obserwatorów
     *
     * @param integer Nowa wartość dla $this->int
     * @return void
     * @access public
     */
    public function setInt($new) {
        $this->int = $new;
        $this->notify();
    }
 
    /**
     * Pobiera wartość właściwości $int
     *
     * @return integer
     * @access public
     */
    public function getInt() {
        return $this->int;
    }
 
}
 
class ExampleObserver implements Observer {
 
    /**
     * Referencja do obserwowanego objektu
     *
     * @access private
     * @var object
     */
    private $subject;
 
    /**
     * 'Imię' obiektu :D
     *
     * @access private
     * @var string
     */
    private $name;
 
    /**
     * Konstruktor
     *
     * @param string Imię obiektu
     * @access public
     */
    public function __construct($name = '') {
        $this->name = $name;
    }
 
    /**
     * Rejestruje się u obiektu obserwowanego
     *
     * @param Subject Obiekt, u którego obserwator ma się zarejestrować
     * @access public
     * @return void
     */
    public function register(Subject $subject) {
        // obserwator powinien wiedzieć, u kogo ma sie zarejestrować
        if($subject instanceof ExampleObservable) {
            $this->subject = $subject;
            $this->subject->attach($this);
        }
    }
 
    /**
     * Wyrejestrowuje się
     *
     * @access public
     * @return void
     */
    public function unregister() {
        if($this->subject) {
            $this->subject->detach($this);
        }
    }
 
    /**
     * Odbiera powiadomienie
     *
     * @param Subject Referencja do obiektu obserwowanego
     * @access public
     * @return void
     */
    public function update(Subject $subject) {
        $this->subject = $subject;
        echo $this->name . ': Odebrano powiadomienie. Liczba ma 
        teraz wartość ' . $this->subject->getInt() . '<br />';
    }
 
}
?>

Przykładowe wykorzystanie wzorca(przy użyciu zdefiniowanych powyżej klas):

<?php
// przykładowy obiekt obserwowany
$e = new ExampleObservable;
 
// dwaj przykładowi obserwatorzy
$a1 = new ExampleObserver('Wacek');
$a2 = new ExampleObserver('Romek');
 
// rejestrujemy obserwatorów
$a1->register($e);
$a2->register($e);
 
// zmieniamy wartość wlaściwości $e i czekamy na rezultat
$e->setInt(923847);
?>

Wyjście tego skryptu będzie miało taką postać:

Wacek: Odebrano powiadomienie. Liczba ma teraz wartość 923847
Romek: Odebrano powiadomienie. Liczba ma teraz wartość 923847

Kiedy używać

Wzorca tego można używać, gdy jeden obiekt kontroluje pracę innych i zachodzi konieczność powiadamiania ich o ewentualnych zmianach. Podany przykład to czysta teoria - nie zawsze przecież każdy obserwator potrzebuje każdej informacji - wtedy to obserwator odpowiednimi algorytmami powinien odfiltrować wysłane informacje, ponieważ (jeszcze raz powtórzyć) obiekt obserwowany(Subject) traktuje wszytstkich obserwatorów jednolicie.

Polecamy również


Błąd przy generowaniu miniatury File missing
Artykuł Observer został uznany za godny umieszczenia na liście artykułów na medal.

Zapraszamy do głosowania na stronie "Propozycje do artykułów na medal"

Strona ta opisuje jeden z Wzorców projektowych.

Wzorce projektowe: Definicja | Zalety | Podział wzorców | Lista wzorców