简单描述

观察者模式(Observer)是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

当对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。它使用的是低耦合的方式。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式UML图

使用场景

事件

Laravel 中的事件就是实现了观察者模式,Wordpress 的钩子机制

支付场景

支付场景下,用户购买一件商品,当支付成功之后三方会回调自身,在这个时候系统可能会有很多需要执行的逻辑(如:更新订单状态,发送邮件通知,赠送礼品…),这些逻辑之间并没有强耦合,因此天然适合使用观察者模式去实现这些功能,当有更多的操作时,只需要添加新的观察者就能实现,完美实现了对修改关闭,对扩展开放的开闭原则。

订阅功能,例如微博的订阅

当我们订阅了某个人的微博账号,当这个人发布了新的消息,就会通知我们。

实例

PHP 已经定义了 2 个接口用于快速实现观察者模式:SplObserverSplSubject

下面以订单为例:当状态变化,需要进行相关处理,例如写日志、短信通知。

<?php
// 实现PHP 自带的 SplObserver 抽象接口
class LogObserver implements SplObserver
{
    public function update($data)
    {
        echo 'write log to file.' . "<br>";
    }
}
// 实现PHP 自带的 SplObserver 抽象接口
class SmsObserver implements SplObserver
{
    public function update($data)
    {
        echo 'send sms' . "<br>";
    }
}

class OrderSubject implements SplSubject
{
    public   $data;
    private  $observers = []; //观察者集合

    public function attach(SplObserver $observer)
    {
        array_push($this->observers, $observer);
    }

    public function detach(SplObserver $observer)
    {
        return false;
    }

    public function notify()
    {
        if(count($this->observers) == 0) return false;
        foreach ($this->observers as $observer)
        {
            $observer->update($this);
        }
    }

    public function change($data)
    {
        // 假设订单数据正确,这部分的逻辑可以根据真实场景进行随意更改,我这里只是简单示范
        if ($data['oid'] == 1 && $data['flag'] == 3) 
        {
            $this->data = $data;
            $this->notify();
        }
    }

}

$order_subject = new OrderSubject();
$order_subject->attach(new LogObserver());//写日志
$order_subject->attach(new SmsObserver());//发短信
$order_subject->change(['oid' => '1', 'flag' => 3]); //订单状态变化,触发观察者

输出结果:
write log to file.
send sms