面向過程編程(結構化編程),我們強調的是程式的分塊結構和流程處理。進入物件導向(OOP)編程領域之後,設計模式成為一項很重要的技術。設計模式處理的是對象的產生及其協作、依賴、耦合等等關係問題。比如,單例模式保證一個類只能被執行個體化一次,原廠模式可以依據不同的條件產生相應的類的執行個體(對象)。而觀察者模式則一般用來實現“事件”處理,構造軟體的事件處理系統。
關於觀察者模式(Observer)的實現方法,本人在一篇部落格文章中論及過(http://blog.why100000.com/?p=744)。但實際上,PHP5.0 以後,SPL(標準PHP庫)提供了方便的對觀察者模式的支援,特別是 PHP5.2 以後,SPL 的功能得到了很大的擴充。
觀察者模式涉及到兩種(兩個或多個)類,一個作為被觀察對象(subject),另一個作為“觀察者”(Observer)。觀察者類監視一個或多個觀察對象的狀態,當其狀態變化時,觀察者會得到通知。
為了支援觀察者模式,SPL 提供了 SplSubject 和 SplObserver 介面。
SplSubject 介面提供了 attach()、detach()、notify() 三個方法。而 SplObserver 介面則提供了 update()方法。
SplSubject 衍生類別維護了一個狀態,當狀態發生變化時 - 比如屬性變化等,就會調用 notify() 方法,這時,之前在 attach() 方法中註冊的所有 SplObserver 執行個體的 update() 方法就會被調用。
class SubjectDemo implements SplSubject
{
private $observers, $value;
public function __construct()
{
//$observers被聲明為數組,表示觀察者可以有多個
$this->observers = array();
}
public function attach(SplObserver $observer)
{
$this->observers[] = $observer;
}
public function detach(SplObserver $observer)
{
if($idx = array_search($observer, $this->observers, true))
unset($this->observers[$idx]);
}
public function notify()
{
foreach($this->observers as $observer)
$observer->update($this);
}
public function setValue($value)
{
$this->value = $value;
$this->notify();
}
public function getValue()
{
return $this->value;
}
public function getObserversNumber()
{
return count($this->observers);
}
}
class ObserverDemo1 implements SplObserver
{
public function update(SplSubject $subject)
{
echo 'The new value is '. $subject->getValue() . '<br>';
}
}
class ObserverDemo2 implements SplObserver
{
public function update(SplSubject $subject)
{
echo 'The Number of Observer(s) is(are) '. $subject->getObserversNumber() . '<br>';
}
}
$subject = new SubjectDemo();
$observer1 = new ObserverDemo1();
$observer2 = new ObserverDemo2();
$subject->attach($observer1);
$subject->attach($observer2);
$subject->setValue(100);
從以上代碼中看出,觀察者可以有多個類。
當 $subject 對象的 setValue() 方法被調用(觸發)時,本身被作為參數傳遞到 $observer1 和 $observer2 對象的 update() 方法中使用。所有觀察者的 update() 函數類似事件處理函數。
要擴充事件處理能力,只要從 SplObserver 介面派生一個子類,編寫其 update() 函數代碼,並附加(attach)到 $subject 對象中即可。
具體到以上代碼,有一個缺陷,就是沒有實現不同的事件,用其對應的類來處理。這個不是觀察者模式本身的問題,需要結合別的模式來解決。
作者:張慶(網眼) 西安 PHP 教育培訓中心 2010-7-6
來自“網眼視界”:http://blog.why100000.com
作者微博:http://t.qq.com/zhangking
“十萬個為什麼”電腦學習網:http://www.why100000.com