摘要:別堵塞了傳輸層大多數(shù)事件處理器被當(dāng)作傳輸層組件。解耦事件處理器開(kāi)始本命題前,我們來(lái)使用一個(gè)示例。假想下把隊(duì)列處理器用來(lái)發(fā)送消息給用戶。盡量避免在事件處理器中摻雜太多的業(yè)務(wù)邏輯。
聲明:本文并非博主原創(chuàng),而是來(lái)自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味的翻譯,能保證90%的原汁性,另外因?yàn)槭抢斫夥g,肯定會(huì)有錯(cuò)誤的地方,歡迎指正。
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處,謝謝!
應(yīng)用體系結(jié)構(gòu):解耦事件處理器 介紹現(xiàn)在我們已經(jīng)介紹了很多使用Laravel 4構(gòu)建健壯應(yīng)用的特性,下面來(lái)深入挖掘更多的細(xì)節(jié)。本章我們將討論諸如隊(duì)列、事件這些眾多事件處理器的解耦,也包括類(lèi)似“類(lèi)事件”結(jié)構(gòu)的路由過(guò)濾。
解耦事件處理器別堵塞了傳輸層
大多數(shù)“事件處理器”被當(dāng)作_傳輸層_組件。換言之,隊(duì)列處理、事件觸發(fā)器、或者一個(gè)外來(lái)請(qǐng)求都被用來(lái)調(diào)用某些調(diào)用處理。要像處理控制器一樣處理這些事件處理器,并避免在其中涉及太多業(yè)務(wù)邏輯。
開(kāi)始本命題前,我們來(lái)使用一個(gè)示例。假想下把隊(duì)列處理器用來(lái)發(fā)送SMS消息給用戶。在發(fā)送消息之后,處理器講發(fā)送了的消息記錄成歷史以便我們知道有哪些用戶收到了這些消息。代碼實(shí)現(xiàn)如下:
class SendSMS{ public function fire($job, $data) { $twilio = new Twilio_SMS($apiKey); $twilio->sendTextMessage(array( "to"=> $data["user"]["phone_number"], "message"=> $data["message"], )); $user = User::find($data["user"]["id"]); $user->messages()->create(array( "to"=> $data["user"]["phone_number"], "message"=> $data["message"], )); $job->delete(); } }
僅測(cè)試這塊代碼,就可能遇到一些問(wèn)題。首先,測(cè)試?yán)щy。Twilio_SMS類(lèi)是在fire方法中實(shí)例化的,這意味著我們無(wú)法使用注入的方式模擬服務(wù)。其次,在處理器中我們直接用到了Eloquent模型,這就給測(cè)試帶來(lái)了另外一個(gè)問(wèn)題,我們必須在方法中進(jìn)行真正的數(shù)據(jù)庫(kù)訪問(wèn)。最后,我們?cè)陉?duì)列之外無(wú)法進(jìn)行SMS消息發(fā)送。我們的SMS消息發(fā)送邏輯完全糅合在Laravel隊(duì)列中了。
通過(guò)將邏輯提取到某一“服務(wù)”中的方法,我們可以將應(yīng)用中的SMS消息發(fā)送邏輯從Laravel的隊(duì)列服務(wù)中解耦出來(lái)。從而可以在應(yīng)用中的任何地方發(fā)送消息。當(dāng)我們進(jìn)行了這種解耦處理,這種重構(gòu)也是我們的代碼變得更加具有可測(cè)性。
讓我們來(lái)修改下代碼:
class User extends Eloquent { /** * Send the User an SMS message * * @param SmsCourierInterface $courier * @param string $message * @return SmsMessage */ public function sendSmsMessage(SmsCourierInterface $courier, $message) { $courier->sendMessage($this->phone_number, $message); return $this->sms()->create(array( "to"=> $this->phone_number, "message"=> $message, )); } }
在這個(gè)重構(gòu)的代碼實(shí)例中,我們將發(fā)送消息的邏輯提取到User模型中。同時(shí)向該方法中注入SmsCourierInterface接口實(shí)現(xiàn)邏輯,使我們更好的測(cè)試邏輯中的方方面面。重構(gòu)了短信發(fā)送邏輯之后,再對(duì)隊(duì)列進(jìn)行重構(gòu):
class SendSMS { public function __construct(UserRepository $users, SmsCourierInterface $courier) { $this->users = $users; $this->courier = $courier; } public function fire($job, $data) { $user = $this->users->find($data["user"]["id"]); $user->sendSmsMessage($this->courier, $data["message"]); $job->delete(); } }
在重構(gòu)的示例中,可以看到,隊(duì)列服務(wù)已經(jīng)足夠輕量。它在隊(duì)列和我們_真正的_應(yīng)用邏輯之間已經(jīng)足夠符合_傳輸層_這個(gè)概念。贊!這意味著我們可以在隊(duì)列之外輕易的發(fā)送消息。最后,讓我們編寫(xiě)一些測(cè)試代碼:
class SmsTest extends PHPUnit_Framework_TestCase { public function testUserCanBeSentSmsMessages() { /** * Arrage ... */ $user = Mockery::mock("User[sms]"); $relation = Mockery::mock("StdClass"); $courier = Mockery::mock("SmsCourierInterface"); $user->shouldReceive("sms")->once()->andReturn($relation); $relation->shouldReceive("create")->once()->with(array( "to" => "555-555-5555", "message" => "Test", )); $courier->shouldReceive("sendMessage")->once()->with( "555-555-5555", "Test" ); /** * Act ... */ $user->sms_number = "555-555-5555"; $user->sendMessage($courier, "Test"); } }其他事件處理器
我們可以改進(jìn)很多這種類(lèi)型的“事件處理器”。將他們限定為簡(jiǎn)單的“傳輸層”來(lái)使用,能將復(fù)雜的業(yè)務(wù)邏輯很好的組織和解耦到框架之外。為了鞏固下這種思想,下面我們舉例一個(gè)路由過(guò)濾器,用它來(lái)驗(yàn)證用戶是否為我們的“高級(jí)”訂閱用戶。
Route::filter("premium", function() { return Auth::user() && Auth::user()->plan == "premium"; });
乍看像是沒(méi)什么問(wèn)題。這么小的代碼能有啥問(wèn)題呢?然而,在這么小的過(guò)濾中,也能意識(shí)到我們將應(yīng)用的實(shí)現(xiàn)細(xì)節(jié)暴漏了出來(lái)。注意,我們?cè)谶^(guò)濾中進(jìn)行對(duì)plan屬性進(jìn)行了檢測(cè)。“級(jí)別”的檢測(cè)邏輯層緊緊的揉進(jìn)了路由、傳輸層。如果我們將“高級(jí)”訂閱用戶的套餐存放到數(shù)據(jù)庫(kù)或者用戶模型中,這里又必須對(duì)我們的路由過(guò)濾器進(jìn)行修改!
相應(yīng)的,做些小的改編:
Route::filter("premium", function() { return Auth::user() && Auth::user()->isPremium(); });
這樣小的改編帶來(lái)的效果是明顯的,付出的代價(jià)也是小的。通過(guò)在模型中對(duì)用戶是否屬于高級(jí)訂閱用戶的判斷,我們將路由中的檢測(cè)邏輯解耦了出來(lái)。我們的過(guò)濾程序不在負(fù)責(zé)檢測(cè)用戶訂閱級(jí)別的職責(zé)。相應(yīng)的,它只需簡(jiǎn)單的詢問(wèn)用戶模型即可?,F(xiàn)在,如果訂閱級(jí)別的判斷存放在數(shù)據(jù)庫(kù)中,路由過(guò)濾不需要更改任何代碼!
該誰(shuí)負(fù)責(zé)?
我們又一次討論了_職責(zé)_的概念。牢記,一個(gè)類(lèi)應(yīng)有的職責(zé)是什么,和他涉及的范圍是明確的。盡量避免在事件處理器中摻雜太多的業(yè)務(wù)邏輯。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/23009.html
摘要:控制只是用來(lái)接收請(qǐng)求并請(qǐng)求邏輯處理類(lèi)。事實(shí)上,業(yè)務(wù)邏輯無(wú)需感知網(wǎng)絡(luò),網(wǎng)絡(luò)僅僅接入應(yīng)用的傳輸機(jī)制,他不應(yīng)超出應(yīng)用中的路由和控制器的范疇。職責(zé)分離是編寫(xiě)健壯應(yīng)用的關(guān)鍵。其他通常,類(lèi)庫(kù)應(yīng)該以規(guī)范組織在我們的應(yīng)用中。 聲明:本文并非博主原創(chuàng),而是來(lái)自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味的翻譯,能保證90%的原汁性,另...
摘要:事件驅(qū)動(dòng)編程是圖形用戶界面和其他應(yīng)用程序例如應(yīng)用程序中使用的主要范例,用于執(zhí)行某些操作來(lái)響應(yīng)用戶輸入。我們來(lái)看一下事件驅(qū)動(dòng)編程帶來(lái)的收益?,F(xiàn)在讓我們看看采用事件驅(qū)動(dòng)編程方法如何實(shí)現(xiàn)上述相同的功能。 在這篇文章中我們將了解到什么是事件驅(qū)動(dòng)編程以及在Laravel中如何開(kāi)始構(gòu)建一個(gè)事件驅(qū)動(dòng)應(yīng)用,同時(shí)我們還將看到如何通過(guò)事件驅(qū)動(dòng)編程來(lái)對(duì)應(yīng)用程序的邏輯進(jìn)行解耦。 在開(kāi)始之前,先說(shuō)明一下這篇文章...
摘要:劃下重點(diǎn),服務(wù)容器是用于管理類(lèi)的依賴和執(zhí)行依賴注入的工具。類(lèi)的實(shí)例化及其依賴的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶的工作原理。 本章將帶領(lǐng)大...
摘要:一個(gè)服務(wù)提供器必須包含至少一種方法。服務(wù)提供器一旦被注冊(cè),就可被用于程序的各個(gè)地方。注意服務(wù)提供器的變量來(lái)自類(lèi)中。啟動(dòng)服務(wù)當(dāng)所有的服務(wù)提供器注冊(cè)之后,他們就變成了已啟動(dòng)狀態(tài)。再次提示,把服務(wù)提供器作為一種組織工具來(lái)使用。 聲明:本文并非博主原創(chuàng),而是來(lái)自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味的翻譯,能保證90%...
摘要:它是良好應(yīng)用設(shè)計(jì)的大原則,包含單一責(zé)任原則開(kāi)放封閉原則里氏替換原則接口分離原則依賴倒置原則讓我們通過(guò)代碼示例來(lái)深究下這五個(gè)原則。實(shí)探單一責(zé)任原則代表一個(gè)類(lèi)有且僅有一個(gè)改變的原因,換言之,一個(gè)類(lèi)的職責(zé)范疇是嚴(yán)謹(jǐn)明確的。 聲明:本文并非博主原創(chuàng),而是來(lái)自對(duì)《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當(dāng)然也不是原汁原味的翻譯,能保證90%的原...
閱讀 1297·2021-09-26 09:55
閱讀 3327·2019-08-30 15:55
閱讀 1045·2019-08-30 15:53
閱讀 2346·2019-08-30 13:59
閱讀 2443·2019-08-29 13:08
閱讀 1160·2019-08-29 12:19
閱讀 3392·2019-08-26 13:41
閱讀 472·2019-08-26 13:24