Observer 观察者

观察者模式 Observer 是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

在观察者模式中,主体是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知

对于需要降低模型间的耦合型,让关联记录的新增、其它服务的调用等拆分开,可以使用观察者模式

观察者模式实现了低耦合,非侵入式的通知与更新机制

OJkLft.png

创建观察者

以员工与部门的管理为例,他们易包括很多关联数据的变更

php artisan make:observer StaffObserver --model=Staff
php artisan make:observer DepartmentObserver --model=Department

完善观察者的几个对应方法,例如请求钉钉、企业微信等第三方接口

namespace App\Observers;

class StaffObserver
{
    public function created (Staff $staff)
    {
        //请求钉钉 API 创建对应账号
    }

    public function updated (Staff $staff)
    {
        //请求钉钉 API 修改账号信息
    }
    
    public function deleted (Staff $staff)
    {
        //请求钉钉 API 停用对应账号
    }
}

注册观察者

AppServiceProvider 中添加观察者的绑定

public function boot ()
{
    Staff::observe(StaffObserver::class);
    Department::observe(DepartmentObserver::class);
    //..
}

现在涉及到 Staff 表与 Department 表的增删改就会自动触发对应方法

Listener 监听者

而另一种解耦方式,是使用事件加监听者

监听者模式,也称为发布-订阅模式,是一种对象之间的行为模式,涉及一对多的依赖关系。在这个模式中,被观察者(Subject)在状态或内容发生变化时,会通知所有注册了的观察者(Observer),使它们能够自动更新自己的信息

每个观察者对象都可以监听一个或多个被观察者对象,当被观察者的状态发生变化时,所有注册的观察者都会收到通知

以一个添加员工事件为例,添加时同时需要为公司的几个平台也增加账户

创建 Event

php artisan make:event StaffCreatedEvent

创建监听器

php artisan make:listener CreateCrmStaff
php artisan make:listener CreateOaStaff
php artisan make:listener CreateBmsStaff

监听者的结构非常简单,主要完善好 handle() 方法

namespace App\Listeners\Staff\StaffCreated;

use App\Events\Staff\StaffCreatedEvent;

class CreateOaStaff
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct ()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param StaffCreatedEvent $event
     * @return void
     */
    public function handle (StaffCreatedEvent $event)
    {
        //..
    }
}

建立对应关系

在事件服务提供者 App\Providers\EventServiceProvider 中通过增加映射关系将两者对应起来

protected $listen = [
    \App\Events\Staff\StaffCreatedEvent::class         => [
        \App\Listeners\Staff\StaffCreated\CreateCrmStaff::class,
        \App\Listeners\Staff\StaffCreated\CreateOaStaff::class,
        \App\Listeners\Staff\StaffCreated\CreateBmsStaff::class,
    ],
]

触发事件

在新增时添加一个 event() 方法来触发:

DB::transaction(function () use ($staff) {
    $staffModel = Staff::findOrNew($staff['id']);
    //...
    $staffModel->save();

    event(new StaffCreatedEvent($staffModel));
    return $staffModel;
});