如何快速上手和使用事件

发布于 2019-12-03 23:07:45

首先理解下什么是事件.

JS 中是有事件这个概念的,点击一下按钮然后出现个弹框,这就触发了一次点击事件,执行的内容就是出现一个弹框.那为什么能触发事件呢?那是因为我提前绑定了点击事件给按钮,所有才会有触发的可能.

这里面便包含了事件的绑定和触发过程,当然后面还会有解绑/通知等操作,这个我们一个一个说.

thinkphp6的事件机制采用了观察者模式,所以要先从什么是观察者模式说起.

一,观察者模式,很简单

"抖音上你关注了一个博主,只要博主有新的视频上传分享,抖音就会通知你,至于你看不看他和博主就没有关系了,只要有新视频,就会一直推送视频给你".这就是一个观察者模式.

观察者模式 => 博主 + 关注博主的人
它解决的是对象间一对多关系下,当主对象改变状态时,依赖对象都会收到通知并各自处理的问题,它让这两边的对象松耦合.

Talk is cheap show me the code,让我们用代码来说明下(就以抖音视频这个案例来说明).

//先来个不用观察者模式的代码
class Bloger {
    public function push() {
        $video = Video::where("***")->find();//找出我的最新上传的一个视频
        if ($video) {
           //开始通知
           MrZhang.newVideo();
           MrWang.newVideo();
           MrsLi.newVideo();
           ...... 
        }
    }
}
$bloger = new Bloger();
$bloger->push();//执行发布视频操作

这样的写法在系统很小的时候会没问题,但抖音上随随便便一个博主就是上万的粉丝,这样的方法不容易扩展,耦合度太高.

  • 比如有人想取消关注,改源代码
  • 比如新增一个关注者,改源代码

如果用上观察者模式,改造上面的代码

//定义一个被观察者接口,具有添加/删除/通知观察者的功能,这样不论是哪个观察者来去,都不用再调整
interface Observed {
    public function addViewer(Observer $observer);
    public function delViewer(Observer $observer);
    public function notify();
}
class Bloger implements Observed {
    public $observers = [];//粉丝池
    public function addViewer(Observer $observer) {
        $key = array_search($observer,$this->observers);
        if ($key === false) {
            $this->observers[] = $observer;
        }
    }
    public function delViewer(Observer $observer) {
        $key = array_search($observer,$this->observers);
        if ($key !== false) {
            unset($this->observers[$key]);
        }
    }
    //通知所有观察者
    public function notify() {
        foreach($this->observers as $observer){
            $observer->update($this);
        }
    }
    
    public function push() {
        $video = Video::where("***")->find();//找出我的最新上传的一个视频
        if ($video) {
           //开始通知
           $this->notify();
        }
    }
}

优化后的代码不再关系要具体通知谁,而是遍历粉丝池通知池内所有人,这样粉丝的变动都不会影响Bloger这个类.

//粉丝接口,所有粉丝都有一个接受通知并做处理的函数
interface Observer(){
    public function update(Observed $observed);
}

//粉丝处理
class MrZhang implements Observer{
    public function update(Observed $observed) {
        echo '立刻看视频';
    }
}
class MrWang implements Observer{
    public function update(Observed $observed) {
        echo '不想看,以后再说';
    }
}
//具体执行过程,添加关注粉丝(也就是绑定)
$bloger = new Bloger();
$bloger->addViewer(new Mrzhang());
$bloger->addViewer(new MrWang());
$bloger->push();//发布视频
......

二,在回过头来看事件

用观察者的思维理解下事件.有很多的观察者,他们都在监听事件是否发送,一旦被触发,这些观察者都会得到通知并做相应处理.

事件:指监听系统的某个行为,实时获取并执行自己逻辑代码的过程

为了便于理解,我们来模拟一个场景,假设有一个登录系统,登录以后需要做一些事情:本地记录日志/告诉朋友我已上线/给管理员发邮件.这个"一些事情"就很多了,未来充满了不确定性,说不好那天需求又变了(经理是处女座).所以系统一定要写的松耦合,这就要使用事件机制.上Code

//一个标准的用户登录逻辑
class User {
    public function login(){
        //登录前的某些操作
        User::login($username,$password);//登录操作
        //登录后的某些操作
    }
}

首先我们要明确观察者和被观察者,观察者有三个(本地记录日志/告诉朋友我已上线/给管理员发邮件),他们都需要登录状态这个通知,所以被观察者就是登录状态.在登录之前我们需要完成观察者的订阅(监听),登录后要完成通知(也就是事件触发),

//定义观察者订阅(监听)
class Log(){
    public function update($user){
        echo '我记录一条登录信息';
    }
}
class Friend(){
    public function update($user){
        echo '朋友们,我上线了';
    }
}
class Admin(){
    public function update($user){
        echo '向管理员发送email';
    }
}

观察者代码自我执行的操作,都有一个$user形参,他会将一些事件信息传递给观察者方法.

//被观察者,完成事件监听和通知
class User {
    public functin __construct(){}
        //添加事件监听
        Event::listen('Userlogin',['Log']);
        Event::listen('Userlogin',['Friend']);
        Event::listen('Userlogin',['Admin']);
    }
    public function login(){
        //登录前的某些操作
        if(false !== User::login($username,$password){
            Event::trigger('Userlogin');//登录后事件触发
        }
    }
}

在trigger这个地方会通知所有正在UserLogin上监听的观察者执行各自的update方法.这就是事件的执行过程.

下一篇文章讲,在thinkphp6中,这个事件机制是如何运行的.

0 条评论

发布
问题