什麼是觀察者模式?
觀察者設計模式能夠更便利地建立查看目標對象狀態的對象,並且提供與核心對象非耦合的指定功能性。
該模式非常簡單:一個物件透過添加一個方法(該方法允許另一個對象,即觀察者 註冊自己)使本身變得可觀察。當可觀察的物件變更時,它會將訊息傳送到已註冊的觀察者。這些觀察者使用該資訊執行的操作與可觀察的物件無關。結果是對象可以相互對話,而不必了解原因。
UML
#此圖詳細說明了一個使用觀察者設計模式的類別設計:
下面是對上圖的說明:
1.MyObject是可觀察對象,它包含一個名為observers的觀察者保護陣列。公共方法addObserver()接受一個觀察者的實例並將其儲存在觀察者陣列內。
2.doSomething()公共方法會被調用,這個方法對MyObject應用狀態變化。隨後,notify()公共方法會被調用,這個方法可遍歷循環觀察者數組。
3.MyObjectObserver有一個名為change()的公用方法,該方法接受MyObject的一個實例。這個特定的觀察者接下來會對MyObject的內容執行某些操作。當在觀察者陣列中找到特定的觀察者時,MyObject的notify()方法會直接呼叫change()方法。
使用實例:
<?php interface Observable{ function attach( Observer $observer ); function detach( Observer $observer ); function notify(); } class login implements Observable{ const LOGIN_USER_UNKNOW = 1; const LOGIN_WRONG_PASS = 2; const LOGIN_ACCESS = 3; private $status = array(); private $observers = array(); public function setStatus( $status, $user, $ip ) { $this->status = array( $status, $user, $ip ); } public function getStatus() { return $this->status; } public function handleLogin( $user, $pass, $ip ) { switch ( mt_rand( 1, 3 ) ) { case 1: $this->setStatus( self::LOGIN_USER_UNKNOW, $user, $ip ); $ret = false; break; case 2: $this->setStatus( self::LOGIN_WRONG_PASS, $user, $ip ); $ret = false; break; case 3: $this->setStatus( self::LOGIN_ACCESS, $user, $ip ); $ret = true; break; } $this->notify(); return $ret; } 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; } public function notify() { foreach ( $this->observers as $obs ) { $obs->update( $this ); } } } interface Observer{ function update( Observable $observable ); } class SecurityMonitor implements Observer{ function update( Observable $observable ) { $status = $observable->getStatus(); if($status[0] == Login::LOGIN_WRONG_PASS){ echo __CLASS__.":".$status[1]."于".$status[2]."登录失败"; } } } $login = new Login(); $login->attach(new SecurityMonitor()); $login->handleLogin('XXX','XXX','127.0.0.1'); ?> 出错时的运行结果: SecurityMonitor:XXX于127.0.0.1登录失败[Finished in 0.1s]
程式碼中可以看到login物件主動加入SecurityMonitor物件觀察。這樣要呼叫Login::getStatus(),SecurityMonitor類別就必須了解更多資訊。雖然呼叫發生於一個ObServable物件上,但無法保證物件也是一個Login物件。為解決這個問題,有一個方法:斷斷續續保持ObServable介面的通用性,由ObServer類別負責保證它們的主體是正確的類型。它們甚至能將自己添加到主體上。
以上是PHP物件導向進階設計模式:觀察者模式使用實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!