观察者模式又叫发布订阅模式, 其本质是在被观察者对象中注册一系列的观察者, 当被观察者的状态发生改变的时候, 通过循环调用一系列观察者对象的方法,进而让观察者对被观察者的状态改变做出相应的响应。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, 或者其他对象
- 事件多级触发, 类似一次框架的运行流程, 接到请求—>初始化框架—>处理请求—>返回相应(这种情况下, 观察者同时也是被观察者)
- 跨系统的消息交换,如消息队列的处理
实践
- 在文件上传时, 可能发生下列动作
- 检查文件类型
- 如果是图片要生成缩略图
- 减少用户的可用空间
- 如果是分享的文件, 还要通知其他人,有人新分享了一个文件
实际中这种场景应该是很多的。
