设计模式之观察者模式

观察者模式又叫发布订阅模式, 其本质是在被观察者对象中注册一系列的观察者, 当被观察者的状态发生改变的时候, 通过循环调用一系列观察者对象的方法,进而让观察者对被观察者的状态改变做出相应的响应。PHP也内建了观察者模式的接口点击这里查看php定义的观察者接口 被观察者接口

优点

  1. 降低了被观察者与观察者之间的耦合性, 双方都是依赖抽象而不是具体的实现(面向接口编程)。

缺点

  1. 由于是一对多的关系而且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

应用场景

  1. 关联行为场景, 例如 a的状态改变会影响到 b,c, 或者其他对象
  2. 事件多级触发, 类似一次框架的运行流程, 接到请求–>初始化框架–>处理请求–>返回相应(这种情况下, 观察者同时也是被观察者)
  3. 跨系统的消息交换,如消息队列的处理

实践

  1. 在文件上传时, 可能发生下列动作
    1. 检查文件类型
    2. 如果是图片要生成缩略图
    3. 减少用户的可用空间
    4. 如果是分享的文件, 还要通知其他人,有人新分享了一个文件

实际中这种场景应该是很多的。