侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Laravel内核分析-设计模式之观察者模式

Laravel  /  管理员 发布于 2年前   662

观察者模式描述:

Laravel 的 Event 事件系统提供了一个简单的观察者模式实现,能够订阅和监听应用中发生的各种事件,在 PHP 的标准库 (SPL) 里甚至提供了三个接口 SplSubject, SplObserver, SplObjectStorage 来让开发者更容易地实现观察者模式,不过我还是想脱离 SPL 提供的接口和特定编程语言来说一下如何通过面向对象程序设计来实现观察者模式,示例是 PHP 代码不过用其他面向对象语言实现起来也是一样的。


模式定义:

1.观察者模式 (Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

2.观察者模式又叫做发布 - 订阅(Publish/Subscribe)模式、模型 - 视图(Model/View)模式、源 - 监听器(Source/Listener)模式或从属者(Dependents)模式。

3.观察者模式的核心在于 Subject 和 Observer 接口,Subject (主题目标) 包含一个给定的状态,观察者 “订阅” 这个主题,将主题的当前状态通知观察者,每次给定状态改变时所有观察者都会得到通知。

4.发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。


模式结构说明:

1.png

Subject  目标抽象类 

ConcreteSubject 具体目标 

Observer 观察者抽象类 

ConcreteObserver 具体观察者


应用举例:

比如在设置用户 (主题) 的状态后要分别发送当前的状态描述信息给用户的邮箱和手机,我们可以使用两个观察者订阅用户的状态,一旦设置状态后主题就会通知的订阅了状态改变的观察者,在两个观察者里面我们可以分别来实现发送邮件信息和短信信息的功能。

1.抽象目标类

abstract class Subject
{
    protected $stateNow;
    protected $observers = [];
    public function attach(Observer $observer)
    {
        array_push($this->observers, $observer);
    }
    public function detach(Observer $ob)
    {
        $pos = 0;
        foreach ($this->observers as $viewer) {
            if ($viewer == $ob) {
                array_splice($this->observers, $pos, 1);
            }
            $pos++;
        }
    }
    public function notify()
    {
        foreach ($this->observers as $viewer) {
            $viewer->update($this);
        }
    }
}

在抽象类中 attach detach 和 notify 都是具体方法,这些是继承才能使用的方法,将由 Subject 的子类使用。


2.具体目标类

class ConcreteSubject extends Subject
{
    public function setState($state) 
    {
        $this->stateNow = $state;
        $this->notify();
    }
    public function getState()
    {
        return $this->stateNow;
    }
}

3.抽象观察者

abstract class Observer
{
    abstract public function update(Subject $subject);
}

在抽象观察者中,抽象方法 update 等待子类为它提供一个特定的实现。


4.具体观察者

class ConcreteObserverDT extends Observer
{
    private $currentState;
    public function update(Subject $subject)
    {
        $this->currentState = $subject->getState();
        echo '<div style="font-size:10px;">'. $this->currentState .'</div>';
    }
}
class ConcreteObserverPhone extends Observer
{
    private $currentState;
    public function update(Subject $subject)
    {
        $this->currentState = $subject->getState();
        echo '<div style="font-size:20px;">'. $this->currentState .'</div>';
    }
}

在例子中为了理解起来简单,我们只是根据不同的客户端设置了不同的内容样式,实际应用中可以真正的调用邮件和短信服务来发送信息。


5.使用观察者模式

class Client 
{
    public function __construct()
    {
        $sub = new ConcreteSubject();
        $obDT = new ConcreteObserverDT();
        $obPhone = new ConcreteObserverPhone();
        $sub->attach($obDT);
        $sub->attach($obPhone);
        $sub->setState('Hello World');
        $sub->notify();
    }
}
$worker = new Client();


何时使用观察者模式:

1.一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

2.一个对象必须通知其他对象,而并不知道这些对象是谁。

3.基于事件触发机制来解耦复杂逻辑时,从整个逻辑的不同关键点抽象出不同的事件,主流程只需要关心最核心的逻辑并能正确地触发事件 (Subject),其余相关功能实现由观察者或者叫订阅者来完成。


总结:

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

2.模式包含四个角色:目标又称为主题,它是指被观察的对象;具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;观察者将对观察目标的改变做出反应;在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致。

3.观察者模式的主要优点在于可以实现表示层和数据逻辑层的分离,并在观察目标和观察者之间建立一个抽象的耦合,支持广播通信;其主要缺点在于如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,而且如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。


转:https://learnku.com/docs/laravel-kernel/design-mode-observer-mode/6919



  • 上一条:
    Laravel内核分析-设计模式之装饰模式
    下一条:
    JWT源码实现逻辑详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Laravel 10.4版本发布(0个评论)
    • 在laravel框架中的5个HTTP客户端技巧分享(0个评论)
    • 在laravel项目中实现密码强度验证功能推荐扩展包:password-strength(0个评论)
    • Laravel Response Classes 响应类使用优化浅析(0个评论)
    • 在Laravel中使用FilePond上传文件及测试用例(0个评论)
    • 近期文章
    • ChatGPT再出新功能,推出插件功能,能联网、搜索了(0个评论)
    • 在go语言中使用GoPDF包把html生成PDF文件示例(0个评论)
    • 在go语言中创建和解析(读取)符号链接示例(0个评论)
    • ubuntu 22.04系统中报错:Python 3.6 is no longer supported by the Python core team...解决方式(0个评论)
    • Laravel 10.4版本发布(0个评论)
    • mysql5.7中实现分区表及分区where in查询示例及分区分表对比浅析(0个评论)
    • nginx + vue配置实现同域名下不同路径访问不同项目(0个评论)
    • 在laravel框架中的5个HTTP客户端技巧分享(0个评论)
    • 在go语言中使用FFmpeg库实现PCM音频文件编码为mp3格式文件流程步骤(0个评论)
    • gopacket免安装Pcap实现驱动层流量抓包流程步骤(0个评论)
    • 近期评论
    • 博主 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 @ xiaoB 你只管努力,剩下的叫给天意;天若有情天亦老,..
    • xiaoB 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 会不会春节放假后又阳一次?..
    • BUG4 在

      你翻墙过吗?国内使用vpn翻墙可能会被网警抓,你需了解的事中评论 不是吧?..
    • 博主 在

      go语言+beego框架中获取get,post请求的所有参数中评论 @ t1  直接在router.go文件中配就ok..
    • Jade 在

      如何在MySQL查询中获得当月记录中评论 Dear zongscan.com team, We can skyroc..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-01
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客