觀察者模式屬於行爲模式,是定義對象間的一種一對多的依賴關係,以便當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並自動刷新。php
當一個對象狀態發生改變後,會影響到其餘幾個對象的改變,這時候能夠用觀察者模式。html
觀察者模式符合接口隔離原則,實現了對象之間的鬆散耦合。ide
發佈-訂閱<Subscribe>模式測試
模型-視圖<View>模式this
源-收聽者<Listener>模式spa
從屬者模式.net
抽象主題(Subject):它把全部觀察者對象的引用保存到一個彙集裏,每一個主題均可以有任何數量的觀察者。抽象主題提供一個接口,能夠增長和刪除觀察者對象。code
具體主題(ConcreteSubject):將有關狀態存入具體觀察者對象;在具體主題內部狀態改變時,給全部登記過的觀察者發出通知。server
抽象觀察者(Observer):爲全部的具體觀察者定義一個接口,在獲得主題通知時更新本身。htm
具體觀察者(ConcreteObserver):實現抽象觀察者角色所要求的更新接口,以便使自己的狀態與主題狀態協調。
在PHP SPL中已經提供SplSubject和SqlOberver接口,源碼以下:
/** * The <b>SplSubject</b> interface is used alongside * <b>SplObserver</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splsubject.php */ interface SplSubject { /** * Attach an SplObserver * @link http://php.net/manual/en/splsubject.attach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to attach. * </p> * @return void * @since 5.1.0 */ public function attach (SplObserver $observer); /** * Detach an observer * @link http://php.net/manual/en/splsubject.detach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to detach. * </p> * @return void * @since 5.1.0 */ public function detach (SplObserver $observer); /** * Notify an observer * @link http://php.net/manual/en/splsubject.notify.php * @return void * @since 5.1.0 */ public function notify (); } /** * The <b>SplObserver</b> interface is used alongside * <b>SplSubject</b> to implement the Observer Design Pattern. * @link http://php.net/manual/en/class.splobserver.php */ interface SplObserver { /** * Receive update from subject * @link http://php.net/manual/en/splobserver.update.php * @param SplSubject $subject <p> * The <b>SplSubject</b> notifying the observer of an update. * </p> * @return void * @since 5.1.0 */ public function update (SplSubject $subject); }
下面咱們根據這兩個spl接口,寫本身的代碼:
<?php header('Content-type:text/html;charset=utf-8'); /** * Class Subject 主題 */ class Subject implements SplSubject { private $_observers = []; /** * 實現添加觀察者方法 * * @param SplObserver $observer */ public function attach(SplObserver $observer) { if (!in_array($observer, $this->_observers)) { $this->_observers[] = $observer; } } /** * 實現移除觀察者方法 * * @param SplObserver $observer */ public function detach(SplObserver $observer) { if (false !== ($index = array_search($observer, $this->_observers))) { unset($this->_observers[$index]); } } /** * 實現提示信息方法 */ public function notify() { foreach ($this->_observers as $observer) { $observer->update($this); } } /** * 設置數量 * * @param $count */ public function setCount($count) { echo "數據量加" . $count . '<br>'; } /** * 設置積分 * * @param $integral */ public function setIntegral($integral) { echo "積份量加" . $integral . '<br>'; } } /** * Class Observer1 觀察者一 */ class Observer1 implements SplObserver { public function update(SplSubject $subject) { $subject->setCount(10); } } /** * Class Observer2 觀察者二 */ class Observer2 implements SplObserver { public function update(SplSubject $subject) { $subject->setIntegral(10); } } /** * Class Client 客戶端 */ class Client { /** * 測試方法 */ public static function test() { // 初始化主題 $subject = new Subject(); // 初始化觀察者一 $observer1 = new Observer1(); // 初始化觀察者二 $observer2 = new Observer2(); // 添加觀察者一 $subject->attach($observer1); // 添加觀察者二 $subject->attach($observer2); // 消息提示 $subject->notify();//輸出:數據量加1 積份量加10 // 移除觀察者一 $subject->detach($observer1); // 消息提示 $subject->notify();//輸出:數據量加1 積份量加10 積份量加10 } } // 執行測試 Client::test();
數據量加10 積份量加10 積份量加10
觀察者和主題之間的耦合度較小;
支持廣播通訊;
因爲觀察者並不知道其它觀察者的存在,它可能對改變目標的最終代價一無所知。這可能會引發意外的更新。
當一個抽象模型有兩個方面,其中一個方面依賴於另外一個方面。
當對一個對象的改變須要同時改變其它對象,而不知道具體有多少個對象待改變。
當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換句話說,你不但願這些對象是緊密耦合的。