摘要:別堵塞了傳輸層大多數事件處理器被當作傳輸層組件。解耦事件處理器開始本命題前,我們來使用一個示例。假想下把隊列處理器用來發送消息給用戶。盡量避免在事件處理器中摻雜太多的業務邏輯。
聲明:本文并非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%的原汁性,另外因為是理解翻譯,肯定會有錯誤的地方,歡迎指正。
歡迎轉載,轉載請注明出處,謝謝!
應用體系結構:解耦事件處理器 介紹現在我們已經介紹了很多使用Laravel 4構建健壯應用的特性,下面來深入挖掘更多的細節。本章我們將討論諸如隊列、事件這些眾多事件處理器的解耦,也包括類似“類事件”結構的路由過濾。
解耦事件處理器別堵塞了傳輸層
大多數“事件處理器”被當作_傳輸層_組件。換言之,隊列處理、事件觸發器、或者一個外來請求都被用來調用某些調用處理。要像處理控制器一樣處理這些事件處理器,并避免在其中涉及太多業務邏輯。
開始本命題前,我們來使用一個示例。假想下把隊列處理器用來發送SMS消息給用戶。在發送消息之后,處理器講發送了的消息記錄成歷史以便我們知道有哪些用戶收到了這些消息。代碼實現如下:
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(); } }
僅測試這塊代碼,就可能遇到一些問題。首先,測試困難。Twilio_SMS類是在fire方法中實例化的,這意味著我們無法使用注入的方式模擬服務。其次,在處理器中我們直接用到了Eloquent模型,這就給測試帶來了另外一個問題,我們必須在方法中進行真正的數據庫訪問。最后,我們在隊列之外無法進行SMS消息發送。我們的SMS消息發送邏輯完全糅合在Laravel隊列中了。
通過將邏輯提取到某一“服務”中的方法,我們可以將應用中的SMS消息發送邏輯從Laravel的隊列服務中解耦出來。從而可以在應用中的任何地方發送消息。當我們進行了這種解耦處理,這種重構也是我們的代碼變得更加具有可測性。
讓我們來修改下代碼:
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, )); } }
在這個重構的代碼實例中,我們將發送消息的邏輯提取到User模型中。同時向該方法中注入SmsCourierInterface接口實現邏輯,使我們更好的測試邏輯中的方方面面。重構了短信發送邏輯之后,再對隊列進行重構:
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(); } }
在重構的示例中,可以看到,隊列服務已經足夠輕量。它在隊列和我們_真正的_應用邏輯之間已經足夠符合_傳輸層_這個概念。贊!這意味著我們可以在隊列之外輕易的發送消息。最后,讓我們編寫一些測試代碼:
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"); } }其他事件處理器
我們可以改進很多這種類型的“事件處理器”。將他們限定為簡單的“傳輸層”來使用,能將復雜的業務邏輯很好的組織和解耦到框架之外。為了鞏固下這種思想,下面我們舉例一個路由過濾器,用它來驗證用戶是否為我們的“高級”訂閱用戶。
Route::filter("premium", function() { return Auth::user() && Auth::user()->plan == "premium"; });
乍看像是沒什么問題。這么小的代碼能有啥問題呢?然而,在這么小的過濾中,也能意識到我們將應用的實現細節暴漏了出來。注意,我們在過濾中進行對plan屬性進行了檢測?!凹墑e”的檢測邏輯層緊緊的揉進了路由、傳輸層。如果我們將“高級”訂閱用戶的套餐存放到數據庫或者用戶模型中,這里又必須對我們的路由過濾器進行修改!
相應的,做些小的改編:
Route::filter("premium", function() { return Auth::user() && Auth::user()->isPremium(); });
這樣小的改編帶來的效果是明顯的,付出的代價也是小的。通過在模型中對用戶是否屬于高級訂閱用戶的判斷,我們將路由中的檢測邏輯解耦了出來。我們的過濾程序不在負責檢測用戶訂閱級別的職責。相應的,它只需簡單的詢問用戶模型即可。現在,如果訂閱級別的判斷存放在數據庫中,路由過濾不需要更改任何代碼!
該誰負責?
我們又一次討論了_職責_的概念。牢記,一個類應有的職責是什么,和他涉及的范圍是明確的。盡量避免在事件處理器中摻雜太多的業務邏輯。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/23009.html
摘要:控制只是用來接收請求并請求邏輯處理類。事實上,業務邏輯無需感知網絡,網絡僅僅接入應用的傳輸機制,他不應超出應用中的路由和控制器的范疇。職責分離是編寫健壯應用的關鍵。其他通常,類庫應該以規范組織在我們的應用中。 聲明:本文并非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%的原汁性,另...
摘要:事件驅動編程是圖形用戶界面和其他應用程序例如應用程序中使用的主要范例,用于執行某些操作來響應用戶輸入。我們來看一下事件驅動編程帶來的收益?,F在讓我們看看采用事件驅動編程方法如何實現上述相同的功能。 在這篇文章中我們將了解到什么是事件驅動編程以及在Laravel中如何開始構建一個事件驅動應用,同時我們還將看到如何通過事件驅動編程來對應用程序的邏輯進行解耦。 在開始之前,先說明一下這篇文章...
摘要:劃下重點,服務容器是用于管理類的依賴和執行依賴注入的工具。類的實例化及其依賴的注入,完全由服務容器自動的去完成。 本文首發于 深入剖析 Laravel 服務容器,轉載請注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請求,又是如何生成響應并最終呈現給用戶的工作原理。 本章將帶領大...
摘要:一個服務提供器必須包含至少一種方法。服務提供器一旦被注冊,就可被用于程序的各個地方。注意服務提供器的變量來自類中。啟動服務當所有的服務提供器注冊之后,他們就變成了已啟動狀態。再次提示,把服務提供器作為一種組織工具來使用。 聲明:本文并非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%...
摘要:它是良好應用設計的大原則,包含單一責任原則開放封閉原則里氏替換原則接口分離原則依賴倒置原則讓我們通過代碼示例來深究下這五個原則。實探單一責任原則代表一個類有且僅有一個改變的原因,換言之,一個類的職責范疇是嚴謹明確的。 聲明:本文并非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%的原...
閱讀 1221·2021-09-26 09:55
閱讀 3183·2019-08-30 15:55
閱讀 961·2019-08-30 15:53
閱讀 2291·2019-08-30 13:59
閱讀 2377·2019-08-29 13:08
閱讀 1104·2019-08-29 12:19
閱讀 3299·2019-08-26 13:41
閱讀 416·2019-08-26 13:24