Observer
Z PHPEdia.pl
Spis treści |
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ż
| | 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
