觀察者模式定義物件間一對多依賴,當主題狀態改變時,自動通知所有觀察者更新。別名:發布-訂閱、模型-視圖、源-監聽。廣泛用於事件系統、框架生命週期鉤子、即時通知。
<?php
/** 抽象主題介面 */
interface Subject {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notifyObservers();
}
/** 具體主題 */
class ConcreteSubject implements Subject {
private $_observers = [];
public function attach(Observer $observer) {
$this->_observers[] = $observer;
}
public function detach(Observer $observer) {
$key = array_search($observer, $this->_observers, true);
if ($key !== false) unset($this->_observers[$key]);
}
public function notifyObservers() {
foreach ($this->_observers as $obs) {
$obs->update();
}
}
}
/** 抽象觀察者介面 */
interface Observer {
public function update();
}
/** 具體觀察者 */
class ConcreteObserver implements Observer {
private $_name;
public function __construct($name) { $this->_name = $name; }
public function update() {
echo "Observer {$this->_name} notified.<br>";
}
}
/** 客戶端測試 */
$subject = new ConcreteSubject();
$subject->attach(new ConcreteObserver('Martin'));
$subject->notifyObservers(); // Martin notified
$subject->attach(new ConcreteObserver('phppan'));
$subject->notifyObservers(); // Martin, phppan notified
$subject->detach($subject->getObservers()[0]); // 移除第一個
$subject->notifyObservers(); // phppan notified
?>
| 優點 | 缺點 |
|---|---|
| 主題與觀察者鬆耦合 | 觀察者不知彼此存在,可能導致意外連鎖更新 |
| 支援廣播通知 | 若觀察者過多或更新耗時,效能下降 |
| 符合開放封閉原則,易擴展新觀察者 | 循環依賴風險(需弱引用或事件總線解耦) |
適用場景: 一個抽象模型有兩個相依層面、一個物件變更需同步更新多個物件但數量不固定、主題不應硬編碼觀察者類別。
大型系統建議引入 Event Dispatcher(如 Symfony EventDispatcher、Laravel Events)作為中介者,解耦主題與觀察者,支援優先級、非同步處理、跨進程通知。觀察者模式是事件驅動架構的基石。
理解觀察者模式,是掌握現代框架事件機制、構建可擴展系統的關鍵一步。