简介
场景
如果想实时跟踪某个对象的状态(例如,对于负责下载的对象,想实时跟踪下载进度),有两种方法:
- 定时轮询:定时访问目标对象的接口,获取其当前状态
- 主动通知:在目标对象发生变化时,主动通知需要知道这个变化的对象
模式定义
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得当一个对象状态发生改变时,所有依赖它的对象将自动得到通知和更新。
观察者模式又叫做发布-订阅(Publish/Subscribe)模式。
模式特点
观察者模式包含四个角色,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系:
- Subject:观察对象
- ConcreteSubject:具体观察对象
- Observer:观察者
- ConcreteObserver:具体观察者
优缺点
- 观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。
- 观察者模式在观察目标和观察者之间建立松耦合,可以独立改变目标或观察者
- 观察者自己觉得是否订阅通知,目标对象对此一无所知
- 新增监控要求时,大型的单体设计不能很好地扩展
PHP 代码示例
AbstractObserver 是观察者抽象类,其中定义了用来被观察目标调用的 update()
方法。AbstractSubject 是观察目标抽象类,其中定义了用来添加观察者的 attach()
方法,用来删除观察者的 detach()
方法,用于通知所有观察者的 notify()
方法。
<?php
abstract class AbstractObserver {
abstract function update(AbstractSubject $subject_in);
}
abstract class AbstractSubject {
abstract function attach(AbstractObserver $observer_in);
abstract function detach(AbstractObserver $observer_in);
abstract function notify();
}
class PatternObserver extends AbstractObserver {
public function update(AbstractSubject $subject) {
writeln(' new favorite patterns: '.$subject->getFavorites());
}
}
class PatternSubject extends AbstractSubject {
private $favoritePatterns = NULL;
private $observers = array();
function attach(AbstractObserver $observer_in) {
$this->observers[] = $observer_in;
}
function detach(AbstractObserver $observer_in) {
//$key = array_search($observer_in, $this->observers);
foreach($this->observers as $okey => $oval) {
if ($oval == $observer_in) {
unset($this->observers[$okey]);
}
}
}
function notify() {
foreach($this->observers as $obs) {
$obs->update($this);
}
}
function updateFavorites($newFavorites) {
$this->favorites = $newFavorites;
$this->notify();
}
function getFavorites() {
return $this->favorites;
}
}
function writeln($line_in) {
echo $line_in."<br/>".PHP_EOL;
}
writeln('BEGIN TESTING OBSERVER PATTERN');
writeln('');
$subject= new PatternSubject();
$observer= new PatternObserver();
$subject->attach($observer);
$subject->updateFavorites('abstract factory, decorator, visitor');
$subject->updateFavorites('abstract factory, observer, decorator');
$subject->detach($observer);
$subject->updateFavorites('abstract factory, observer, paisley');
writeln('END TESTING OBSERVER PATTERN');