摘要:事件驅(qū)動編程是圖形用戶界面和其他應(yīng)用程序例如應(yīng)用程序中使用的主要范例,用于執(zhí)行某些操作來響應(yīng)用戶輸入。我們來看一下事件驅(qū)動編程帶來的收益。現(xiàn)在讓我們看看采用事件驅(qū)動編程方法如何實(shí)現(xiàn)上述相同的功能。
在這篇文章中我們將了解到什么是“事件驅(qū)動編程”以及在Laravel中如何開始構(gòu)建一個(gè)事件驅(qū)動應(yīng)用,同時(shí)我們還將看到如何通過事件驅(qū)動編程來對應(yīng)用程序的邏輯進(jìn)行解耦。
在開始之前,先說明一下這篇文章主要是闡述事件驅(qū)動這種編程思維和理念的,所以不會涉及到Laravel Events的方方面面。如果你需要更全面地了解Laravel Events和它的各種用法可以訪問Laravel Events文檔來了解詳細(xì)信息。
何為事件驅(qū)動編程在我們深入事件驅(qū)動應(yīng)用之前,我們先看一下在維基百科里對事件驅(qū)動編程的定義:
事件驅(qū)動編程是一種編程模式,其中的程序流由諸如用戶動作(鼠標(biāo)點(diǎn)擊,按鍵)、傳感器輸出或來自其他程序/線程的消息等事件來決定確定。事件驅(qū)動編程是圖形用戶界面和其他應(yīng)用程序(例如JavaScript Web應(yīng)用程序)中使用的主要范例,用于執(zhí)行某些操作來響應(yīng)用戶輸入。
事件驅(qū)動應(yīng)用程序會響應(yīng)用戶的動作,然后執(zhí)行對應(yīng)的代碼來響應(yīng)用戶的動作。
Laravel Events通過上面的定義,事件是發(fā)生在應(yīng)用程序中的動作。Javascript的事件是像鼠標(biāo)點(diǎn)擊、鼠標(biāo)懸浮、按下鍵盤這樣的用戶動作。在Laravel中事件是發(fā)生在應(yīng)用程序中的動作,像郵件通知、記錄日志、用戶注冊、CRUD操作等。Laravel Events系統(tǒng)提供了簡易的觀察者模式實(shí)現(xiàn),讓開發(fā)者能夠訂閱和監(jiān)聽發(fā)生在應(yīng)用中的動作。
應(yīng)用中有些事件是由Laravel框架自動發(fā)起。比如說當(dāng)使用Eloquent Model執(zhí)行create、save、update或者delete操作時(shí)Laravel將分別發(fā)起created、saved、updated、和deleted事件。如果需要的話我們可以監(jiān)聽這些事件從而執(zhí)行相應(yīng)的代碼來完成自己的需求。除了Laravel框架自動發(fā)起的事件,我們還可以根據(jù)自己應(yīng)用的需要讓Laravel發(fā)起我們自己定義的事件。比如說你可以發(fā)起一個(gè)userRegistered事件,在事件處理程序中發(fā)送用戶驗(yàn)證郵件好讓新注冊的用戶能夠驗(yàn)證自己的郵箱。
發(fā)起一個(gè)事件并不會讓應(yīng)用程序執(zhí)行任何相應(yīng)的操作,我們必須在事件處理程序中對被發(fā)起的事件進(jìn)行相應(yīng)地回應(yīng)。Laravel Events由兩部分組成Event Handler和Event Listener。Event Handler中包含了發(fā)起事件相關(guān)的信息。Event Listener監(jiān)聽事件對象并對事件進(jìn)行回應(yīng),Event Listener是我們實(shí)現(xiàn)事件邏輯的地方。在Laravel中Event類文件被存放在app/Events目錄,Listener類文件被存放在app/Listeners目錄。
為何使用事件驅(qū)動編程我們已經(jīng)了解事件驅(qū)動應(yīng)用和Laravel Events的概念了,你可能會好奇為什么要采用事件驅(qū)動這種方法來構(gòu)建你的應(yīng)用程序。我們來看一下事件驅(qū)動編程帶來的收益。
首先,事件是一種解耦應(yīng)用程序各個(gè)方面的好方法,因?yàn)閱蝹€(gè)事件可以有多個(gè)不依賴于彼此的監(jiān)聽器。通過解耦,不會因?yàn)槟闶褂昧瞬贿m合域邏輯的代碼而污染了代碼庫。其次,由于應(yīng)用程序是松散耦合的,你可以輕松擴(kuò)展應(yīng)用程序的功能,而不必打亂/重寫應(yīng)用程序或應(yīng)用程序的某些其他功能。
應(yīng)用示例現(xiàn)在假設(shè)新用戶注冊了我們的應(yīng)用程序后,應(yīng)用程序會給用戶發(fā)送一封歡迎郵件,同時(shí)會自動給用戶訂閱應(yīng)用上的每周新聞簡報(bào)。在不應(yīng)用事件驅(qū)動方式的情況下代碼往往是如下這樣:
// 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 email Mail::to($user)->send(new WelcomeToSiteName($user)); // Sign user up for weekly newsletter Newsletter::subscribe($user->email, [ "FNAME": $user->fname, "LNAME": $user->lname ], "SiteName Weekly"); // login newly registered user $this->guard()->login($user); return redirect("/home"); }
你可以看到發(fā)送歡迎郵件和訂閱新聞簡報(bào)的邏輯緊密耦合到了register方法里, 根據(jù)關(guān)注點(diǎn)分離原則,register方法不應(yīng)該關(guān)心發(fā)送歡迎郵件和訂閱新聞簡報(bào)的具體實(shí)現(xiàn)。你可能會覺得發(fā)送歡迎郵件和訂閱新聞放到register方法里也沒什么,但是如果在注冊時(shí)除了發(fā)送郵件還要給用戶發(fā)送短信呢?繼續(xù)寫在register方法里:
public function register(Request $request) { // validate input // create user and persist in database // send welcome email Mail::to($user)->send(new WelcomeToSiteName($user)); // send SMS Nexmo::message()->send([ "to" => $user->phone_number, "from" => "SiteName", "text" => "Welcome and thanks for signup on SiteName." ]); // Sign user up for weekly newsletter Newsletter::subscribe($user->email, [ "FNAME": $user->fname, "LNAME": $user->lname ], "SiteName Weekly"); // login newly registered user return redirect("/home"); }
可以看到代碼庫開始變得臃腫。現(xiàn)在讓我們看看采用事件驅(qū)動編程方法如何實(shí)現(xiàn)上述相同的功能。
// 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 created event(new UserRegistered($user)); // login newly registered user $this->guard()->login($user); return redirect("/home"); }
一旦創(chuàng)建了用戶,UserRegistered事件就會被觸發(fā)。回想一下,我們之前提到,發(fā)起一個(gè)事件后應(yīng)用并不會自己做任何事情,我們需要監(jiān)聽UserRegistered事件并執(zhí)行必要的操作。讓我們創(chuàng)建UserRegistered事件類和SendWelcomeMail以及SignupForWeeklyNewsletter監(jiān)聽器類:
php artisan make:event UserRegistered php artisan make:listener SendWelcomeMail --event=UserRegistered php artisan make:listener SignupForWeeklyNewsletter --event=UserRegistered
事件和監(jiān)聽器之間的對應(yīng)關(guān)系需要注冊到EventServiceProvider的$listen屬性里:
protected $listen = [ UserRegistered::class => [ SendWelcomeMail::class, SignupForWeeklyNewsletter::class, ], ];
打開app/Events/UserRegistered.php文件更新它的構(gòu)造方法:
public $user; public function __construct(User $user) { $this->user = $user; }
聲明$user為public,它將被傳遞給監(jiān)聽器,而監(jiān)聽器可以用它來執(zhí)行必要的邏輯。接下來,事件監(jiān)聽器將在其handle方法中接收到事件實(shí)例。在handle方法中,我們可以執(zhí)行響應(yīng)事件的操作。
// app/Listeners/SendWelcomeMail.php public function handle(UserRegistered $event) { // send welcome email Mail::to($event->user)->send(new WelcomeToSiteName($event->user)); } // app/Listeners/SignupForWeeklyNewsletter.php public function handle(UserRegistered $event) { // Sign user up for weekly newsletter Newsletter::subscribe($event->user->email, [ "FNAME": $event->user->fname, "LNAME": $event->user->lname ], "SiteName Weekly"); }
可以看到通過事件驅(qū)動的方式我們讓register方法的代碼盡可能的少并且專注于用戶注冊這件事上,其它的邏輯由UserRegistered事件的監(jiān)聽器來負(fù)責(zé),現(xiàn)在如果說我們想在用戶注冊后發(fā)送短信給新注冊的用戶,我們所要做的就是創(chuàng)建一個(gè)新的事件監(jiān)聽器來監(jiān)聽UserRegistered事件何時(shí)被觸發(fā)
php artisan make:listener SendWelcomeSMS --event=UserRegistered // app/Listeners/SendWelcomeSMS.php public function handle(UserRegistered $event) { // send SMS Nexmo::message()->send([ "to" => $event->user->phone_number, "from" => "SiteName", "text" => "Welcome and thanks for signup on SiteName." ]); }
注:記得要更新EventServiceProvider里的$listen屬性
Conclusion在這篇文章中,我們已經(jīng)能夠理解事件驅(qū)動的編程是什么,事件驅(qū)動的應(yīng)用程序是什么以及Laravel事件是什么。我們還研究了事件驅(qū)動應(yīng)用程序的優(yōu)勢。但是,像跟所有有積極影響的編程概念一樣,它也有缺點(diǎn)。事件驅(qū)動型應(yīng)用程序的主要缺點(diǎn)是讓程序流變得復(fù)雜了,尤其一些剛接觸開發(fā)的人可能很難真正理解應(yīng)用程序的流程。以上面的實(shí)現(xiàn)為例,通過register方法我們并不能直觀地看到程序在創(chuàng)建用戶后會向新用戶發(fā)送一封歡迎郵件,并將其注冊到新聞通訊中。
所以在開發(fā)中應(yīng)該根據(jù)場景創(chuàng)造性地使用它,利用它的優(yōu)勢為你的應(yīng)用程序解耦,而不是過度使用它。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/28430.html
摘要:前言年底了不太忙,最近一段時(shí)間也一直在研究,就想寫篇關(guān)于比較深一點(diǎn)的教程系列啥的,于是就找到站長給開了寫教程的渠道。優(yōu)點(diǎn)的就是為藝術(shù)家創(chuàng)造的框架,它也是工程化的趨勢。項(xiàng)目維護(hù)方便也是事實(shí)。如果有遇到問題可以直接在教程下面留言。 前言 年底了不太忙,最近一段時(shí)間也一直在研究laravel,就想寫篇關(guān)于laravel比較深一點(diǎn)的教程系列啥的,于是就找到站長給開了寫教程的渠道。由于第一次寫,...
摘要:初步嘗試既然最常見的注冊命令的方式是修改類中的,那么一般正常人都會從這邊開始下手。又要自己取出實(shí)例,又要自己調(diào)用方法,調(diào)用方法之前還有自己先把實(shí)例化這么繁瑣,肯定不是運(yùn)行時(shí)添加命令的最佳實(shí)踐,所以我決定繼續(xù)尋找更優(yōu)解。 本文首發(fā)于我的博客,原文鏈接:https://blessing.studio/best-... 雖然 Laravel 官方文檔提供的添加 Artisan Command...
摘要:上例的功能塊定義了如下節(jié)點(diǎn)樹入口節(jié)點(diǎn)是面板,結(jié)合該節(jié)點(diǎn)的函數(shù)書寫特點(diǎn),我們接著介紹最佳實(shí)踐如何處理功能塊之內(nèi)的編程。 本文介紹 React + Shadow Widget 應(yīng)用于通用 GUI 開發(fā)的最佳實(shí)踐,只聚焦于典型場景下最優(yōu)開發(fā)方法。分上、下兩篇講解,上篇概述最佳實(shí)踐,介紹功能塊劃分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...
摘要:編程書籍的整理和收集最近一直在學(xué)習(xí)深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的東西,發(fā)現(xiàn)深入地去學(xué)習(xí)就需要不斷的去提高自己算法和高數(shù)的能力然后也找了很多的書和文章,隨著不斷的學(xué)習(xí),也整理了下自己的學(xué)習(xí)筆記準(zhǔn)備分享出來給大家后續(xù)的文章和總結(jié)會繼續(xù)分享,先分享一部分的 編程書籍的整理和收集 最近一直在學(xué)習(xí)deep learning深度學(xué)習(xí)和機(jī)器學(xué)習(xí)的東西,發(fā)現(xiàn)深入地去學(xué)習(xí)就需要不斷的去提高自己算法和高數(shù)的能力然后...
閱讀 1571·2021-09-24 10:38
閱讀 1498·2021-09-22 15:15
閱讀 3059·2021-09-09 09:33
閱讀 905·2019-08-30 11:08
閱讀 638·2019-08-30 10:52
閱讀 1253·2019-08-30 10:52
閱讀 2345·2019-08-28 18:01
閱讀 521·2019-08-28 17:55