观察者模式对于PHP而言,有几个内置的接口实现,相关的模式,分别是 SplSubject
SubObserver 和 SplObjectStoarge,相比uml类图,我比较喜欢用更通俗易懂的关系图解释现象,如下图。
被观察者 通过映射对象 存储了所有的 观察者对应的对象映射,然后在被观察者发生改变的时候,会循环映射对像,通知所有的观察者
,直接上代码。
主体(被观察者)类:
/**
* @package: 观察者模式
* 所谓的观察者,通俗一点讲
主体 (被观察者 A) SplSubject
存储容器 (观察者映射表) SplObjectStorage
观察者 B1,B2,B3... SplObserver
A一段发生改变,B1,B2,B3... 都会收到相应的通知
*/
//------------主体 被观察者
class Subject implements SplSubject
{
private $observers;
private $data;
public function setStorage()
{
$this->observers = new SplObjectStorage();
}
public function attach(SplObserver $observer)
{
$this->observers->attach($observer);
}
public function detach(SplObserver $observer)
{
$this->observers->detach($observer);
}
public function notify()
{
foreach($this->observers as $observer){
$observer->update($this);
}
}
public function setData($data)
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
}
观察者:
//---------------观察者
//---------也就是说 每一个观察者 只要实现 SplObserver 并实现方法update 就能被通知到
class Observer implements SplObserver
{
private $name = '';
public function __construct($name)
{
$this->name = $name;
}
public function update(SplSubject $subject)
{
echo $this->name.":";
var_dump($subject->getData());
}
}
调用:
// 实例使用
$A = new Subject();
$A->setStorage();
$B1 = new Observer('B1');
$B2 = new Observer('B2');
$B3 = new Observer('B3');
$A->attach($B1);
$A->attach($B2);
$A->attach($B3);
$A->setData('123');
$A->notify();
$A->detach($B2);
$A->setData('456');
$A->notify();
调用结果:
B1:string(3) "123"
B2:string(3) "123"
B3:string(3) "123"
B1:string(3) "456"
B3:string(3) "456"
可以看到每个存在于映射对象里的对象都收到了相应的通知。其实具体的思路,我们不应该仅仅局限于
php所给的SplObjectStorage 存储,我们可以扩展到redis 及其他,SplSubject 和 SplObserver 也是,只要
实现 被观察者 能获取每一个观察者,并能调用相应的观察者通知方法,有点类似消息队列的定时推送,