图片:塞尔达传说旷野之息海拉鲁大陆

在这篇文章中我们将了解到什么是“事件驱动编程”以及在Laravel中如何开始构建一个事件驱动应用,同时我们还将看到如何通过事件驱动编程来对应用程序的逻辑进行解耦。

在开始之前,先说明一下这篇文章主要是阐述事件驱动这种编程思维和理念的,所以不会涉及到Laravel Events的方方面面。如果你需要更全面地了解Laravel Events和它的各种用法可以访问Laravel Events文档来了解详细信息。

何为事件驱动编程

在我们深入事件驱动应用之前,我们先看一下在维基百科里对事件驱动编程的定义:

事件驱动编程是一种编程模式,其中的程序流由诸如用户动作(鼠标点击,按键)、传感器输出或来自其他程序/线程的消息等事件来决定确定。事件驱动编程是图形用户界面和其他应用程序(例如JavaScript Web应用程序)中使用的主要范例,用于执行某些操作来响应用户输入。

事件驱动应用程序会响应用户的动作,然后执行对应的代码来响应用户的动作。

Laravel Events

通过上面的定义,事件是发生在应用程序中的动作。 Javascript的事件是像鼠标点击、鼠标悬浮、按下键盘这样的用户动作。在Laravel中事件是发生在应用程序中的动作,像邮件通知、记录日志、用户注册、CRUD操作等。 LaravelEvents系统提供了简易的观察者模式实现,让开发者能够订阅和监听发生在应用中的动作。

应用中有些事件是由Laravel框架自动发起。比如说当使用 EloquentModel执行create、save、update或者delete操作时Laravel将分别发起 createdsavedupdated、和 deleted事件。如果需要的话我们可以监听这些事件从而执行相应的代码来完成自己的需求。除了Laravel框架自动发起的事件,我们还可以根据自己应用的需要让Laravel发起我们自己定义的事件。比如说你可以发起一个 userRegistered事件,在事件处理程序中发送用户验证邮件好让新注册的用户能够验证自己的邮箱。

发起一个事件并不会让应用程序执行任何相应的操作,我们必须在事件处理程序中对被发起的事件进行相应地回应。 LaravelEvents由两部分组成 EventHandlerEventListenerEventHandler中包含了发起事件相关的信息。 EventListener监听事件对象并对事件进行回应, EventListener是我们实现事件逻辑的地方。在Laravel中Event类文件被存放在 app/Events目录,Listener类文件被存放在 app/Listeners目录。

为何使用事件驱动编程

我们已经了解事件驱动应用和 LaravelEvents的概念了,你可能会好奇为什么要采用事件驱动这种方法来构建你的应用程序。我们来看一下事件驱动编程带来的收益。

首先,事件是一种解耦应用程序各个方面的好方法,因为单个事件可以有多个不依赖于彼此的监听器。通过解耦,不会因为你使用了不适合域逻辑的代码而污染了代码库。其次,由于应用程序是松散耦合的,你可以轻松扩展应用程序的功能,而不必打乱/重写应用程序或应用程序的某些其他功能。

应用示例

现在假设新用户注册了我们的应用程序后,应用程序会给用户发送一封欢迎邮件,同时会自动给用户订阅应用上的每周新闻简报。在不应用事件驱动方式的情况下代码往往是如下这样:

// without event-driven approach
public function register(Request $request)
{// validate input$this->validate($request->all(), ['name' => 'required','email' => 'required|unique:users','password' => 'required|min:6|confirmed',]);// create user and persist in database$user = $this->create($request->all());// send welcome emailMail::to($user)->send(new WelcomeToSiteName($user));// Sign user up for weekly newsletterNewsletter::subscribe($user->email, ['FNAME': $user->fname,'LNAME': $user->lname], 'SiteName Weekly');// login newly registered user$this->guard()->login($user);return redirect('/home');
}

你可以看到发送欢迎邮件和订阅新闻简报的逻辑紧密耦合到了 register方法里, 根据关注点分离原则, register方法不应该关心发送欢迎邮件和订阅新闻简报的具体实现。你可能会觉得发送欢迎邮件和订阅新闻放到 register方法里也没什么,但是如果在注册时除了发送邮件还要给用户发送短信呢?继续写在 register方法里:

public function register(Request $request)
{// validate input// create user and persist in database// send welcome emailMail::to($user)->send(new WelcomeToSiteName($user));// send SMSNexmo::message()->send(['to' => $user->phone_number,'from' => 'SiteName','text' => 'Welcome and thanks for signup on SiteName.']);// Sign user up for weekly newsletterNewsletter::subscribe($user->email, ['FNAME': $user->fname,'LNAME': $user->lname], 'SiteName Weekly');// login newly registered userreturn redirect('/home');
}

可以看到代码库开始变得臃肿。现在让我们看看采用事件驱动编程方法如何实现上述相同的功能。

// with event-driven approach
public function register(Request $request)
{// validate input$this->validate($request->all(), ['name' => 'required','email' => 'required|unique:users','password' => 'required|min:6|confirmed',]);// create user and persist in database$user = $this->create($request->all());// fire event once user has been createdevent(new UserRegistered($user));// login newly registered user$this->guard()->login($user);return redirect('/home');
}

一旦创建了用户, UserRegistered事件就会被触发。回想一下,我们之前提到,发起一个事件后应用并不会自己做任何事情,我们需要监听 UserRegistered事件并执行必要的操作。让我们创建 UserRegistered事件类和 SendWelcomeMail以及 SignupForWeeklyNewsletter监听器类:

php artisan make:event UserRegistered
php artisan make:listener SendWelcomeMail --event=UserRegistered
php artisan make:listener SignupForWeeklyNewsletter --event=UserRegistered

事件和监听器之间的对应关系需要注册到EventServiceProvider的 $listen属性里:

protected $listen = [UserRegistered::class => [SendWelcomeMail::class,SignupForWeeklyNewsletter::class,],
];

打开 app/Events/UserRegistered.php文件更新它的构造方法:

public $user;
public function __construct(User $user)
{$this->user = $user;
}

声明$user为public,它将被传递给监听器,而监听器可以用它来执行必要的逻辑。接下来,事件监听器将在其handle方法中接收到事件实例。在handle方法中,我们可以执行响应事件的操作。

// app/Listeners/SendWelcomeMail.php
public function handle(UserRegistered $event)
{// send welcome emailMail::to($event->user)->send(new WelcomeToSiteName($event->user));
}
// app/Listeners/SignupForWeeklyNewsletter.php
public function handle(UserRegistered $event)
{// Sign user up for weekly newsletterNewsletter::subscribe($event->user->email, ['FNAME': $event->user->fname,'LNAME': $event->user->lname], 'SiteName Weekly');
}

可以看到通过事件驱动的方式我们让register方法的代码尽可能的少并且专注于用户注册这件事上,其它的逻辑由 UserRegistered事件的监听器来负责,现在如果说我们想在用户注册后发送短信给新注册的用户,我们所要做的就是创建一个新的事件监听器来监听UserRegistered事件何时被触发

php artisan make:listener SendWelcomeSMS --event=UserRegistered
// app/Listeners/SendWelcomeSMS.php
public function handle(UserRegistered $event)
{// send SMSNexmo::message()->send(['to' => $event->user->phone_number,'from' => 'SiteName','text' => 'Welcome and thanks for signup on SiteName.']);
}

注:记得要更新EventServiceProvider里的$listen属性

Conclusion

在这篇文章中,我们已经能够理解事件驱动的编程是什么,事件驱动的应用程序是什么以及Laravel事件是什么。我们还研究了事件驱动应用程序的优势。但是,像跟所有有积极影响的编程概念一样,它也有缺点。事件驱动型应用程序的主要缺点是让程序流变得复杂了,尤其一些刚接触开发的人可能很难真正理解应用程序的流程。以上面的实现为例,通过 register方法我们并不能直观地看到程序在创建用户后会向新用户发送一封欢迎邮件,并将其注册到新闻通讯中。

所以在开发中应该根据场景创造性地使用它,利用它的优势为你的应用程序解耦,而不是过度使用它。

用事件驱动编程解救臃肿的代码相关推荐

  1. Laravel最佳实践--事件驱动编程

    在这篇文章中我们将了解到什么是"事件驱动编程"以及在Laravel中如何开始构建一个事件驱动应用,同时我们还将看到如何通过事件驱动编程来对应用程序的逻辑进行解耦. 在开始之前,先说 ...

  2. python事件驱动编程_Python事件驱动编程

    事件驱动的编程侧重于事件.最终,程序的流程取决于事件.到目前为止,我们处理顺序或并行执行模型,但具有事件驱动编程概念的模型称为异步模型.事件驱动的编程取决于始终侦听新传入事件的事件循环.事件驱动编程的 ...

  3. Javascript事件驱动编程

    Javascript事件驱动编程 基本概述 JS是采用事件驱动的机制来响应用户操作的,也就是说当用户对某个html元素进行操作的时候,会产生一个时间,该时间会驱动某些函数来处理. PS:这种方式和Ja ...

  4. ASP.NET基础与入门:WebForm,事件驱动编程,Page类

    注:因为这个暑假做了一个ASP.NET的项目(WebForms模式),暑假期间太忙没有来得及整理,现在统一梳理下知识(有些我认为可以跟HTML共通的就没记) 推荐几个学习ASP.NET的网站: W3S ...

  5. java太臃肿_Java简洁开发技巧,减少繁琐臃肿的代码

    Java简洁开发技巧,减少繁琐臃肿的代码 Szx • 2020 年 12 月 09 日 消除if...else的方法 在项目实际开发中使用if...else判断的场景非常多,上面只是其中几种场景.下面 ...

  6. 事件驱动编程、消息驱动编程、数据驱动编程

    事件驱动 基本概念 窗口/组件 事件 消息(队列) 事件响应(服务处理程序) 调度算法 进程/线程 非阻塞I/O 程序的执行可以看成对CPU,内存,IO资源一次占用 现代操作系统支持多任务,可以分时复 ...

  7. 【C/C++服务器开发】事件驱动、事件驱动架构、事件驱动编程及设计模式

    文章目录 一.事件驱动 二.事件驱动编程 事件驱动和异步IO 看图说话讲事件驱动模型 三.C/C++实现事件驱动 四.常用的C/C++事件驱动库 一.事件驱动 首先我们来看看百度百科的介绍. 所谓事件 ...

  8. php http面向对象编程实例,PHP面向对象编程——PHP对象引用实例代码

    /* ?* WEB开发笔记 www.chhua.com 每日练习 PHP面向对象编程--PHP对象引用实例代码 ?*/ /*代码演示 ?* */ class HelloWorld {//被引用对象 ? ...

  9. 嵌入式编程C语言提高代码效率的14种方法

    嵌入式编程C语言提高代码效率的14种方法 1.在可能的情况下使用typedef替代define.当然有时候你无法避免define,但是typedef更好. typedef int* INT_PTR; ...

最新文章

  1. Mysql8.0 3306端口无法远程连接
  2. 【数据结构与算法】之深入解析“通配符匹配”的求解思路与算法示例
  3. 对话框Dialog总结(转)
  4. c语言聊天程序socket,今天打的代码。基于TCP的聊天程序。
  5. 海洋主题绘画_深圳举办风帆时代海洋绘画作品展,展出作品600余件
  6. 5.6亿人没有存款、人均负债13万,大数据揭示负债累累的年轻人
  7. Java虚拟机专题之class文件结构(读书笔记)
  8. C语言丨线性表(二):线性链表(单链表)
  9. MySQL打不开用户_mysql打不开了
  10. ASA 5505 配置
  11. 教你如何Mac上手动配置静态IP上网
  12. SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别 及动态查询中的标识符函数QUOTENAME
  13. Atitit 图片 验证码生成attilax总结
  14. 自定义Openstack图标
  15. 安卓实现播放器app
  16. 计算机本地连接xp,xp系统本地连接不见了的解决方法
  17. java学习之路2--简单工厂模式实现饮料自动贩卖机
  18. linux ubuntu系统 ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)数据
  19. bidi(双向文字)与RTL布局总结
  20. 卓越人生的两大利器——任务分解与保持节奏

热门文章

  1. 技术分享连载(二十七)
  2. 【工具使用系列】关于 MATLAB 反馈神经网络,你需要知道的事
  3. Struts2之初识篇(一)——与struts的区别和基本配置
  4. kubernets1.52安装文档
  5. 中国拟修订保守国家秘密法 严防通过互联网泄密
  6. PHP vscode+XDebug 远程断点调试服务器上的代码
  7. HTTP之Cookie
  8. 判断系统大小端方法分析与总结
  9. 1.3Python快速入门
  10. android3D动画,绕y轴旋转