觀察者模式用於實現對對象進行觀察:一旦主體對象狀態發生改變,與之關聯的觀察者對象會收到通知,並進行相應操做。php
舉個例子說明:
假設一個這樣的情景,當公司有一個新員工入職了,入職的當天,HR須要爲他辦理入職手續,網管須要給他配好電腦和辦公用品,部門主管須要帶他熟悉部門。傳統的編程方式,就是在員工入職這個事件發生的代碼以後直接加入處理邏輯,當後續咱們須要增長處理邏輯時(好比員工入職後增長培訓),代碼會變得難以維護。這種方式是耦合的,侵入式的,增長新的邏輯須要改變事件主題的代碼。運用觀察者模式,將員工的入職做爲事件,其餘的處理邏輯都作爲觀察者的操做,那麼,當之後須要再增長更多的邏輯時,新增邏輯代碼就會很方便。具體代碼實現以下。編程
首先定義一個觀察者接口,全部的觀察者都實現這個接口(爲何要定義成接口呢?由於每個觀察者的具體行爲須要具體去實現,用接口定義一個統一的方法,具體的實現交給觀察者去實現)工具
interface observer { public function update(); }
再定義一個事件生成器的抽象類,用來使繼承它的事件都具備通知觀察者的能力。this
abstract class EventGenerator { private $observers = []; //定義一個添加觀察者的方法 public function addOberver(Observer $observer) { $this->observers[] = $observer; } //定義一個通知觀察者的方法 public function notify() { foreach($this->observers as $observer) { $observer->update(); } } }
而後再來定義事件類.net
class event extends EventGenerator { //定義一個觸發觀察者的方法 public funtion trigger() { echo "Event <br/>"; //開始通知觀察者 $this->notify(); } }
開始使用code
$event = new event(); $event->trigger();
這個時候,當咱們要在事件發生的時候增長別的操做,只須要新增觀察者就能夠了server
新增一個觀察者對象
class Observer1 implements Observer { public function update() { echo "操做1<br/>"; } }
而後使用的時候就是繼承
$event = new event(); // 增長觀察者 $event->addObserver(new Observer1); $event->trigger();
若是須要在事件發生後再增長操做,只需再新增相應的觀察者便可。接口
觀察者模式解除了主體和具體觀察者的耦合,讓耦合的雙方都依賴於抽象,而不是依賴具體。從而使得各自的變化都不會影響另外一邊的變化。下降對象之間的耦合度以達到解耦的目的,符合"開閉原則"的要求。
PHP 經過內置的 SPL 擴展提供了對觀察者模式的原生支持,其中的觀察者由 3 個元素組成 : SplObserver 接口、 SplSubject 接口和 SplObjectStorage 工具類。下面是利用 SPL 實現觀察者模式的代碼。SPL 的地址見這裏。
class MyObserver1 implements SplObserver { public function update(SplSubject $subject) { echo __CLASS__ . ' - ' . $subject->getName(); } } class MyObserver2 implements SplObserver { public function update(SplSubject $subject) { echo __CLASS__ . ' - ' . $subject->getName(); } } class MySubject implements SplSubject { private $observers; private $name; public function __construct($name) { $this->observers = new SplObjectStorage(); $this->name = $name; } public function attach(SplObserver $observer) { $this->observers->attach($observer); } public function detach(SplObserver $observer) { $this->observers->detach($observer); } public function notify() { foreach ($this->observers as $observer) { $observer->update($this); } } public function getName() { return $this->name; } } $observer1 = new MyObserver1(); $observer2 = new MyObserver2(); $subject = new MySubject("test"); $subject->attach($observer1); $subject->attach($observer2); $subject->notify(); /* 輸出: MyObserver1 - test MyObserver2 - test */ $subject->detach($observer2); $subject->notify(); /* 輸出: MyObserver1 - test */