[TOC]php
咱們來看看報紙和雜誌的訂閱是怎麼回事:數據結構
觀察者模式就像訂閱報紙,知識名稱不太同樣:出版社改成「主題」(Subject),訂閱者稱爲「觀察者」(Observer)。實現觀察者模式的方式不僅一種,可是包含Subject和Observer接口的類設計的作法最多見。this
主題能夠註冊、註銷觀察者,當數據改變時,能夠通知觀察者;全部的觀察者必須繼承觀察者接口,這個接口只有一個update()方法,當主題的狀態被改變時調用。主題繼承 SplSubject,這個是PHP內置觀察者模式主題接口;觀察者繼承SplObserver;同時,主題中用SplObjectStorage來存儲觀察者列表。spa
這個是主題:.net
<?php namespace Observer2; use SplObserver; class Subject implements \SplSubject { // 觀察者對象 private $observers; private $upd_data = 10; private $upd_msg = '還不應吃飯'; public function __construct() { // 數據結構對象容器 $this->observers = new \SplObjectStorage(); } /** * 註冊觀察者 * * Attach an SplObserver * @link https://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) { $this->observers->attach($observer); } /** * 註銷觀察者 * * Detach an observer * @link https://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) { $this->observers->detach($observer); } /** * 通知觀察者 * Notify an observer * @link https://php.net/manual/en/splsubject.notify.php * @return void * @since 5.1.0 */ public function notify() { // 循環調用觀察者自身的update方法 if ($this->observers->count() > 0) { /** @var \SplObserver $observer */ foreach ($this->observers as $observer) { $observer->update($this); } } } /** * 數據改變,同時通知觀察者 * * @param $upd_data */ public function updData($upd_data) { $this->upd_data = $upd_data; // 當數據改變時,再須要通知觀察者的地方調用 notify $this->notify(); } /** * 消息改變,同時通知觀察者 * * @param $upd_msg */ public function updMsg($upd_msg) { $this->upd_msg = $upd_msg; // 這個 notify 也能夠不寫在方法中,靈活運用 $this->notify(); } /** * @return mixed */ public function getUpdData() { return $this->upd_data; } /** * @return mixed */ public function getUpdMsg() { return $this->upd_msg; } }
有一個貓貓觀察者:設計
<?php namespace Observer2; use SplSubject; class CatObserver implements \SplObserver { /** * 從主題那裏獲得通知 * * Receive update from subject * @link https://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) { // 這個 $subject 一開始比較難理解,最後發現確實很聰明 // 我以爲這種實現方式最好,具體要獲得哪些更新,由註冊觀察者的主題決定 // 觀察者不知道主題的細節,只知道實現了觀察者接口 /** * @var Subject $subject */ $listen_data = $subject->getUpdData(); $listen_msg = $subject->getUpdMsg(); echo 'I am 貓貓觀察者,I get new data:' . $listen_data . ';msg:' . $listen_msg; echo '<br>'; } }
還有一個狗狗觀察者:code
<?php namespace Observer2; class DogObserver implements \SplObserver { public function update(\SplSubject $subject) { /** * @var Subject $subject */ $listen_data = $subject->getUpdData(); $listem_msg = $subject->getUpdMsg(); echo 'I am 狗狗觀察者,data:' . $listen_data . ';msg:' . $listem_msg; echo '<br>'; } }
來看一下調用吧:server
<?php include 'CatObserver.php'; include 'Subject.php'; include 'DogObserver.php'; // 觀察者 $catObserver = new \Observer2\CatObserver(); $dogObserver=new Observer2\DogObserver(); // 主題 $subject = new \Observer2\Subject(); // 註冊觀察者 $subject->attach($catObserver); $subject->attach($dogObserver); // 主題有所變化,觀察者獲得對應的變化 $subject->updData(12); $subject->updMsg('你媽媽喊你回家吃飯');
顯示結果:對象
I am 貓貓觀察者,I get new data:12;msg:還不應吃飯 I am 狗狗觀察者,data:12;msg:還不應吃飯 I am 貓貓觀察者,I get new data:12;msg:你媽媽喊你回家吃飯 I am 狗狗觀察者,data:12;msg:你媽媽喊你回家吃飯
把個人例子弄懂,你也應該能理解觀察者模式了。繼承
來看一下你學到了什麼:
00原則--對象之間鬆耦合設計。
觀察者模式--在對象之間定義一對多的依賴,這樣一來,當一個對象改變狀態,依賴他的對象就會收到通知,並自動更新。