Jak pisałem w poprzednich postach, programowanie obiektowe wiąże się ściśle z pewnymi praktykami i wzorcami, które ułatwiają rozwiązywanie problemów napotykanych przez programistów. W poprzednich wpisach opisywałem wzorce kreacyjne, czyli takie, które odpowiadały za tworzenie obiektów. W tym wpisie opiszę wzorzec behawioralny. Wzorce behawioralne opisują relację pomiędzy obiektami oraz ich zachowania.
Wzorzec obserwator w PHP
Wzorzec obserwatora(ang. Observer pattern) odpowiedzialny jest za powiadamianie obiektu A o zmianie stanu obiektu B. Mówiąc ludzkim językiem, gdy coś się wydarzy w obiekcie A to informuje on obiekt B o tym, a obiekt B reaguje odpowiednio na to wydarzenie. Obiekt A jest nazywany „obserwowanym”, a obiekt B jest „obserwatorem”.
Na diagramie wygląda to tak:
W przykładzie, który przedstawię Subject to obiekt obserwowany, a ConreteObserver to klasy implementujące interfejs Observer.
interface Observer{ public function update(Observable $observable); }
Zawiera deklarację metody update, która jest wywoływana w obiekcie obserwującym podczas zmiany stanu obserwatora.
Następną ważną częścią wzorca jest abstrakcyjna klasa Observable, która jest rozszerzana poprzez klasy chcące być „obserwowane”. Klasa ta zawiera kluczowe elementy potrzebne do działania wzorca takie jak:
- lista obserwatorów
- metoda attach(Observer $observer) dodająca obserwatora
- metoda detach(Observer $observer) usuwająca obserwatora
- metoda notify(), która powiadamia obserwatorów o zmianie stanu obiektu
abstract class Observable { private $observers = array(); public function attach(Observer $observer) { $this->observers[] = $observer; } public function detach(Observer $observer) { foreach($this->observers as $okey => $oval) { if ($oval == $observer) { unset($this->observers[$okey]); } } } public function notify() { foreach($this->observers as $obs) $obs->update($this); } }
Gdy mamy kod obserwatora i obiektu obserwowanego możemy utworzyć właściwe klasy, które wykorzystają mechanizm wzorca. W przykładzie utworzyłem trzy klasy obserwatorów oraz jedną klasę dla obiektu obserwowanego.
Obserwatorzy:
class SmsNotification implements Observer{ public function __construct() { } public function update(Observable $observable) { $this->sendSms($observable->getNews()); } private function sendSms($news) { echo "wysylam sms z nowa wiadomoscia $news<br>"; } } class EmailNotification implements Observer{ public function __construct() { } public function update(Observable $observable) { $this->sendEmail($observable->getNews()); } private function sendEmail($news) { echo "wysylam email z nowa wiadomoscia $news<br>"; } } class NewsModel implements Observer{ public function __construct() { } public function update(Observable $observable) { $this->addToDb($observable->getNews()); } private function addToDb($news) { echo 'dodaje newsy do bazy danych<br>'; } }
Obserwatorzy implementują interfejs Observer, dzieki czemu mogą użyć metody update(), która występuje w tym interfejsie. Metoda ta wywoływana będzie z klasy obiektu obserwowanego podczas zmiany jego stanu.
Ten sam przykład z wykorzystaniem SPL
https://gist.github.com/anonymous/0309420667a901a4b7ce
Miałem napisać właśnie przykład z wykorzystaniem SPL, dzięki za gist-a.