观察者模式又叫发布订阅模式, 其本质是在被观察者对象中注册一系列的观察者, 当被观察者的状态发生改变的时候, 通过循环调用一系列观察者对象的方法,进而让观察者对被观察者的状态改变做出相应的响应。PHP也内建了观察者模式的接口点击这里查看php定义的观察者接口 被观察者接口
优点
- 降低了被观察者与观察者之间的耦合性, 双方都是依赖抽象而不是具体的实现(面向接口编程)。
缺点
- 由于是一对多的关系而且php是同步执行, 所以其中含有执行效率低的观察者,将影响整体的执行效率,也会加大php的内存占用(所有的监听者都会被实例化并存储), 所以要根据实际需要来使用。(使用异步是一种解决方案)
应用
<?php
// 被观察者, 使用标准库提供的对象存储,存储所有的观察者
class FileUpload implements SplSubject
{
private $storage;
private $filename;
public function __construct($filename)
{
echo '上传了一张新图片' . $filename . PHP_EOL;
$this->storage = new SplObjectStorage();
$this->filename = $filename;
}
public function attach(SplObserver $observer)
{
$this->storage->attach($observer);
}
public function detach(SplObserver $observer)
{
$this->storage->detach($observer);
}
public function notify()
{
foreach ($this->storage as $obj){
$obj->update($this);
}
}
public function getFilename(){
return $this->filename;
}
}
<?php
// 通知朋友, 新分享了一个文件
class Friends implements SplObserver
{
public function update(SplSubject $subject)
{
echo '收到了一个分享' . $subject->getFilename() . PHP_EOL;
}
}
<?php
// 接收到通知的时候生成缩略图
class Thumbnail implements SplObserver{
public function update(SplSubject $subject)
{
echo $subject->getFilename() . '生成缩略图成功' . PHP_EOL;
}
}
<?php
// 场景类
require_once "FileUpload.php";
require_once "Thumbnail.php";
require_once "Friends.php";
$fileL = new FileUpload('图片1.png');
$thumbnail = new Thumbnail();
$fileL->attach($thumbnail); // 增加一个监听者
$fileL->attach(new Friends());
$fileL->detach($thumbnail); // 不想生成缩略图也可以取消监听
$fileL->notify();
结果: 上传了一张新图片图片1.png 图片1.png生成缩略图成功 收到了一个分享图片1.png
应用场景
- 关联行为场景, 例如 a的状态改变会影响到 b,c, 或者其他对象
- 事件多级触发, 类似一次框架的运行流程, 接到请求–>初始化框架–>处理请求–>返回相应(这种情况下, 观察者同时也是被观察者)
- 跨系统的消息交换,如消息队列的处理
实践
- 在文件上传时, 可能发生下列动作
- 检查文件类型
- 如果是图片要生成缩略图
- 减少用户的可用空间
- 如果是分享的文件, 还要通知其他人,有人新分享了一个文件
实际中这种场景应该是很多的。