觀察者模式的核心是把客戶元素(觀察者)從一個中心類(主體)中分離出來。當主體知道時間發生時,觀察者需要被通知到。同時,不需要主體和觀察者之間進行寫入程式碼。
《設計模式》中對Observer模式的意圖的描述是:“定義對象間的一對多的依賴關係,當一個對象的狀態發生變化時,所有依賴於它的對象都能到得到通知並自動更新”
Observer模式用到的幾條物件導向的原則也值得關註:
1.對象自我負責:Observer對象有多種,但是都從Subject對象手機所需資訊,並自己完成相應的操作。
2.抽象類別(介面):Observer類(介面)表示了“需要通知的對象”這一概念,它為目標提供了一個通知observer的公用介面。
3.多態封裝:Subject並不知道與那種觀察者通訊。實際上,observer類封裝了各種特定的observer.這以為這如果我在未來有新的observer,不需要更改subject類。
《深入php物件導向模式與實踐》給給出的例子:
假設我們有一個login類處理使用者的登陸資訊,當使用者登入時,根據使用者的登入狀態,做相應的動作。如果不對login對象和相應的動作做硬式編碼話。observer模式是一個極佳的選擇。
Observable 介面(主體):
interface Observable{ function attach(Observer $observer); function detach(Observer $observer); function notify();}
具體的Login(登入主體):
class login implements Observable{ const LOGIN_ACCESS = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_USER_UNKNOWN = 3; private $status = array(); private $observers; public function __construct(){ $this->observers = array(); } public function attach(Observer $observer){ $this->observers[] = $observer; } public function detach(Observer $observer){ $newObservers = array(); foreach($this->observers as $obs){ if($obs != $observer){ $newObservers[] = $obs; } } $this->observers = $newObservers; } private function setStatus($status,$user,$ip){ $this->status = array($status,$user,$ip); } public function getStatus(){ return $this->status; } public function notify(){ foreach($this->observers as $obs){ $obs->update($this); } } public function handlerLogin( $user,$pass,$ip){ switch(rand(1,3)){ case 1: $this->setStatus(Self::LOGIN_ACCESS,$user,$ip); $ret = true;break; case 2: $this->setStatus(Self::LOGIN_WRONG_PASS,$user,$ip); $ret = false;break; case 3: $this->setStatus(Self::LOGIN_USER_UNKNOWN,$user,$ip); $ret = true;break; } }}
觀察者介面:
interface Observer{ function update(Observable $observable);}
抽象的login觀察者類:
abstract class LoginObserver implements Observer{ private $login; public function __construct(Login $login){ $this->login = $login; $login->attach($this); } public function update(Observable $observable){ if($observable == $this->login){ $this->doUpdate($observable); } } abstract private function doUpdate( Login $login );}
具體的觀察者類:
//觀察者1:登入失敗時候發送郵件class SecurityMonitor extends LoginObserver{ private function doUpdate( Login $login ){ $status = $login->getStatus(); if($status[0] == Login::LOGIN_WRONG_PASS){ print __CLASS__."\tsending mail to sysadmin"; } }}//觀察者2:記錄登入日誌class GeneralLogger extends LoginObserver{ private function doUpdate(Login $login){ $status = $login->getStatus(); //LOG print __CLASS__."[status]:{$status}\tadd login data to log"; }}//觀察者3:設定cookieclass PartnerShipTool extends LoginObserver{ private function doUpdate(Login $login){ $status = $login->getStatus(); //COOKIE print __CLASS__."[Cookie]:{$status}\t set cookie to a list"; }}
各個類之間的類圖關係如所示:
PHP內建的SPL擴充提供了對觀察者模式的原生態支援。其中的觀察者有三個元素組成,SplObserver,SplSubject,SplStorage.其中SplObserver,SplSubject都是介面。SplStorage是個工具類,用於更好滴儲存對象和刪除對象。
有SPL的支援,實現觀察者模式更加方便一些了。