Laravel核心解读--观察者模式
观察者模式
Laravel的Event事件系统提供了一个简单的观察者模式实现,能够订阅和监听应用中发生的各种事件,在PHP的标准库(SPL)里甚至提供了三个接口SplSubject
, SplObserver
, SplObjectStorage
来让开发者更容易地实现观察者模式,不过我还是想脱离SPL提供的接口和特定编程语言来说一下如何通过面向对象程序设计来实现观察者模式,示例是PHP代码不过用其他面向对象语言实现起来也是一样的。
模式定义
观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
观察者模式的核心在于Subject和Observer接口,Subject(主题目标)包含一个给定的状态,观察者“订阅”这个主题,将主题的当前状态通知观察者,每次给定状态改变时所有观察者都会得到通知。
发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。
模式结构说明
- Subject 目标抽象类
- ConcreteSubject 具体目标
- Observer 观察者抽象类
- ConcreteObserver 具体观察者
应用举例
比如在设置用户(主题)的状态后要分别发送当前的状态描述信息给用户的邮箱和手机,我们可以使用两个观察者订阅用户的状态,一旦设置状态后主题就会通知的订阅了状态改变的观察者,在两个观察者里面我们可以分别来实现发送邮件信息和短信信息的功能。
抽象目标类
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
的子类使用。
具体目标类
class ConcreteSubject extends Subject
{public function setState($state) {$this->stateNow = $state;$this->notify();}public function getState(){return $this->stateNow;}
}
抽象观察者
abstract class Observer
{abstract public function update(Subject $subject);
}
在抽象观察者中,抽象方法update
等待子类为它提供一个特定的实现。
具体观察者
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>';}
}
在例子中为了理解起来简单,我们只是根据不同的客户端设置了不同的内容样式,实际应用中可以真正的调用邮件和短信服务来发送信息。
使用观察者模式
class Client
{public function __construct(){$sub = new ConcreteSubject();$obDT = new ConcreteObserverDT();$obPhone = new ConcreteObserverPhone();$sub->attach($obDT);$sub->attach($obPhone);$sub->setState('Hello World');}
}$worker = new Client();
何时使用观察者模式
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 基于事件触发机制来解耦复杂逻辑时,从整个逻辑的不同关键点抽象出不同的事件,主流程只需要关心最核心的逻辑并能正确地触发事件(Subject),其余相关功能实现由观察者或者叫订阅者来完成。
总结
- 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新。
- 模式包含四个角色:目标又称为主题,它是指被观察的对象;具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;观察者将对观察目标的改变做出反应;在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致。
- 观察者模式的主要优点在于可以实现表示层和数据逻辑层的分离,并在观察目标和观察者之间建立一个抽象的耦合,支持广播通信;其主要缺点在于如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,而且如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
本文已经收录在系列文章Laravel源码学习里,欢迎访问阅读。
Laravel核心解读--观察者模式相关推荐
- Laravel核心解读--服务容器(IocContainer)
Laravel的核心是IocContainer, 文档中称其为"服务容器",服务容器是一个用于管理类依赖和执行依赖注入的强大工具,Laravel中的功能模块比如 Route.Elo ...
- Laravel核心解读--完结篇
过去一年时间写了20多篇文章来探讨了我认为的Larave框架最核心部分的设计思路.代码实现.通过更新文章自己在软件设计.文字表达方面都有所提高,在刚开始决定写Laravel源码分析地文章的时候我地期望 ...
- Laravel核心解读--完结篇 1
过去一年时间写了20多篇文章来探讨了我认为的Larave框架最核心部分的设计思路.代码实现.通过更新文章自己在软件设计.文字表达方面都有所提高,在刚开始决定写Laravel源码分析地文章的时候我地期望 ...
- Laravel核心解读--控制器
控制器 控制器能够将相关的请求处理逻辑组成一个单独的类, 通过前面的路由和中间件两个章节我们多次强调Laravel应用的请求在进入应用后首现会通过Http Kernel里定义的基本中间件 protec ...
- Laravel核心解读--Console内核
Console内核 上一篇文章我们介绍了Laravel的HTTP内核,详细概述了网络请求从进入应用到应用处理完请求返回HTTP响应整个生命周期中HTTP内核是如何调动Laravel各个核心组件来完成任 ...
- Laravel核心解读--Contracts契约
Contracts Laravel 的契约是一组定义框架提供的核心服务的接口, 例如我们在介绍用户认证的章节中到的用户看守器契约IllumninateContractsAuthGuard 和用户提供器 ...
- Laravel核心解读 -- 用户认证系统(基础介绍)
用户认证系统(基础介绍) 使用过Laravel的开发者都知道,Laravel自带了一个认证系统来提供基本的用户注册.登录.认证.找回密码,如果Auth系统里提供的基础功能不满足需求还可以很方便的在这些 ...
- Laravel核心解读 -- 事件系统
事件系统 Laravel 的事件提供了一个简单的观察者实现,能够订阅和监听应用中发生的各种事件.事件机制是一种很好的应用解耦方式,因为一个事件可以拥有多个互不依赖的监听器.laravel 中事件系统由 ...
- Laravel核心解读--控制器 1
控制器 控制器能够将相关的请求处理逻辑组成一个单独的类, 通过前面的路由和中间件两个章节我们多次强调Laravel应用的请求在进入应用后首现会通过Http Kernel里定义的基本中间件 protec ...
最新文章
- python--迭代器的实现
- 简历写了会Kafka,面试官90%会让你讲讲acks参数对消息持久化的影响
- 图说数据中心空调系统原理和架构
- 鸿蒙智慧屏电视,鸿蒙os全面推送,立刻买了一台华为智慧屏电视s pro65
- 课时18:函数:灵活即强大
- Java线程面试题 Top 50
- Jackson学习笔记
- c语言课设报告时钟vc环境,C语言课程设计报告模拟时钟转动程序.doc
- Linux运行级别介绍
- 铸造行业ERP管理软件的开发
- 2022-2027年中国苹果树种植行业市场全景评估及发展战略规划报告
- 记一次解决eclipse复制粘贴不能用问题
- 大学四年恍然若梦,一直走在路上
- [论文阅读] Meta-Weight-Net: Learning an Explicit Mapping For Sample Weighting
- 为什么这么多人会选择单页设计?
- 网易云MUSIC年终奖0.5?听到消息我扔了耳机
- 自然语言处理python培训
- HIT-哈工大数据结构-作业5(C++)
- ESP32 ESP-IDF看门狗TWDT
- java解决udp可靠性,由于UDP协议提供的是不可靠的服务,因此,可以被淘汰掉。...