Laravel : 使用動作類整理你的代碼(翻譯)

友偶閱網(wǎng)文一篇衣吠,頭中尾英,閱不能颈抚,遂中譯之。原文鏈接 :Keeping your Laravel applications DRY with single action classes

“這段代碼該放在哪里责静?”恐怕是在談?wù)搼?yīng)用結(jié)構(gòu)時最經(jīng)常提起的問題「乔牛“我應(yīng)該放在 Controller 里嗎灾螃?還是 Model ?還是哪里揩徊?”睦焕,雖然 Laravel 是個十分靈活的框架,但要解答這個問題也不總能簡單明了靴拱。

當(dāng)你知道你的應(yīng)用程序只有一個接入點的時候,把邏輯寫在 Controller 是完全沒問題的猾普。但如今應(yīng)用一般都會有好幾個接入點共用同一個功能袜炕。

例如,很多應(yīng)用都會有一個用戶注冊的表單初家,提交到 Controller 偎窘,然后根據(jù)是否成功注冊來返回有用的信息。在移動端應(yīng)用的場景下溜在,一般都會有個使用 JSON 格式返回的 API 專門用于用戶注冊陌知。而且利用 Laravel 的 artisan 命令來創(chuàng)建用戶也很常見,尤其是在項目前期的開發(fā)階段掖肋。

這些重復(fù)代碼的確看上去沒什么毛病仆葡,但如果就這樣讓業(yè)務(wù)邏輯繼續(xù)擴充下去,例如:你希望給新注冊用戶發(fā)一封提醒郵件志笼,那么你需要在兩個 Controller 里同時加上這個邏輯沿盅。所以為了代碼能夠整潔優(yōu)雅起來,我們需要把它放到其他地方去纫溃。

別把服務(wù)類神化了

一開始腰涧,可以先臨時創(chuàng)建一個類,把所有針對某個業(yè)務(wù)邏輯的代碼整理起來紊浩,例如:

這樣看上去就好多了窖铡;我們可以直接從 Controller 里調(diào)用 User 的 create()/ delete() ,通過任意途徑返回結(jié)果坊谁。然而這方式有個問題:我們處理業(yè)務(wù)邏輯的時候很少使用一種模式费彼。

例如我們有這個業(yè)務(wù)邏輯:當(dāng)用戶創(chuàng)建賬號的時候,需要創(chuàng)建一篇新的博客呜袁。如果我們繼續(xù)使用剛才的模式敌买,我們需要創(chuàng)建 BlogService 然后使其作為依賴注入到 UserService 中:

很顯然,當(dāng)我們的應(yīng)用變得越來越大阶界,會有越來越多的服務(wù)類虹钮,有些還依賴了 5 個甚至 6 個其他的服務(wù)類聋庵,代碼像被貓玩過的毛線球剪不斷理還亂 —— 我們無論如何都要避免這種結(jié)局。

引入動作類

如果我們不使用里面塞了幾個方法的單一服務(wù)類芙粱,而是把邏輯切分到好幾個類里面呢祭玉?我在最近的好幾個工程里都使用了這種模式,結(jié)果十分不錯春畔。

首先脱货,我們暫時先把“服務(wù)”這個抽象而且模糊的術(shù)語丟掉,然后引入“動作”類律姨,并且賦予以下定義:

  • 一個動作類振峻,它的名字應(yīng)該要能夠讓人一眼看出它是干什么的,例如:CreateOrder, ConfirmCheckout, DeleteProduct, AddProductToCart,…..
  • 動作類應(yīng)該只擁有一個公開接口(API)择份。理想情況下應(yīng)該用統(tǒng)一的名字扣孟,例如 handle(), execute() 這樣,方便我們需要在動作上實現(xiàn)一些模式荣赶,例如適配器凤价。
  • 動作類不應(yīng)該關(guān)心 RequestResponse。動作類不處理任何 Request拔创,也不產(chǎn)生任何 Response利诺,因為這是 Controller 的責(zé)任。
  • 動作類可以依賴其他的動作剩燥。
  • 當(dāng)處理業(yè)務(wù)邏輯的時候慢逾,遇到不能返回期望內(nèi)容的情況下,必須拋出異常灭红,讓調(diào)用者(或者 Laravel 的 ExceptionHandler)去負(fù)責(zé)渲染或者返回錯誤信息氛改。

創(chuàng)建 CreateUser 動作

現(xiàn)在,讓我們用 CreateUser 動作類來重構(gòu)剛才的例子比伏。

你可能覺得奇怪胜卤,為什么代碼要在 Email 存在的情況下拋出異常,這個不應(yīng)該是在請求的時候就應(yīng)該驗證一次嗎赁项?當(dāng)然應(yīng)該讓驗證器去做這件事葛躏,不過,強制動作類遵循業(yè)務(wù)邏輯是一個好主意悠菜。這樣做不但能夠讓業(yè)務(wù)邏輯更明確(不用過多考慮異常情況)舰攒,也更容易調(diào)試。

下面是我們使用動作類重構(gòu)后的控制器:

現(xiàn)在我們再也不用在注冊流程更改的時候同時修改兩邊的代碼悔醋,干凈整潔摩窃。

內(nèi)嵌動作

當(dāng)我們需要往應(yīng)用里倒入 1000 個用戶的時候,我們可以寫一個依賴 CreateUser 的動作類:

干凈整潔,簡單易懂猾愿。在這里我們在 Collection::map() 里重用了 CreateUser 鹦聪,返回一個集合,裝著新鮮出爐的用戶們蒂秘。我們可以稍作優(yōu)化:當(dāng)有重復(fù)郵件的時候泽本,我們可以通過返回 Null 對象,或者往 Logger 里丟 INFO 姻僧,隨你喜歡规丽。

裝飾一下 Actions

現(xiàn)在,假設(shè)我們要往日志里記錄每一個用戶的注冊撇贺。我們可以直接把代碼放到動作自身上赌莺,但我們也可以使用裝飾器模式

然后松嘶,使用 Laravel 的 IoC 容器雄嚣,我們可以把 LogCreateUser 類綁在 Createuser 類上,這樣當(dāng)我們就總能在需要后者的時候把原型注入進(jìn)去:

這樣做甚至更容易地通過環(huán)境變量或者配置控制日志的開啟和關(guān)閉:

總結(jié)

使用這種模式大概會在開始先產(chǎn)生一大堆的類喘蟆。當(dāng)然,為了減少一下文章篇幅讀起來比較方便鼓鲁,這里只舉了這個簡單的用戶注冊例子蕴轨。當(dāng)復(fù)雜度增加的時候,這個模式的價值就開始體現(xiàn)出來了 — — 因為你清楚這些邊界清楚分工明確的代碼在哪骇吭。

使用動作類的好處:

  • 使用小物件管理領(lǐng)域邏輯可避免重復(fù)代碼以及增加可重用性橙弱,Keep things SOLID。
  • 易于針對不同的場景做獨立測試燥狰。
  • 清晰易懂棘脐、有意義的命名讓理解項目變得更加容易
  • 跨項目一致性:避免代碼七零八落地分布在 ControllerModels 等等……

而且龙致,這些實踐都是基于我最近這些年使用 Laravel 的經(jīng)驗以及我寫過的項目總結(jié)出來的蛀缝。它們對我來說非常管用,以至于我甚至在中小型項目里使用目代。

我非常希望能夠與你一同交流分享屈梁,如果你有不同的實踐方式那就最好不過了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榛了,一起剝皮案震驚了整個濱河市在讶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌霜大,老刑警劉巖构哺,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異战坤,居然都是意外死亡曙强,警方通過查閱死者的電腦和手機残拐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旗扑,“玉大人蹦骑,你說我怎么就攤上這事⊥畏溃” “怎么了眠菇?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長袱衷。 經(jīng)常有香客問我捎废,道長,這世上最難降的妖魔是什么致燥? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任登疗,我火速辦了婚禮,結(jié)果婚禮上嫌蚤,老公的妹妹穿的比我還像新娘辐益。我一直安慰自己,他們只是感情好脱吱,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布智政。 她就那樣靜靜地躺著,像睡著了一般箱蝠。 火紅的嫁衣襯著肌膚如雪续捂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天宦搬,我揣著相機與錄音牙瓢,去河邊找鬼。 笑死间校,一個胖子當(dāng)著我的面吹牛矾克,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播憔足,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聂渊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了四瘫?” 一聲冷哼從身側(cè)響起汉嗽,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎找蜜,沒想到半個月后饼暑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年弓叛,在試婚紗的時候發(fā)現(xiàn)自己被綠了彰居。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡撰筷,死狀恐怖陈惰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情毕籽,我是刑警寧澤抬闯,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站关筒,受9級特大地震影響溶握,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒸播,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一睡榆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧袍榆,春花似錦胀屿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至馏艾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奴愉,已是汗流浹背琅摩。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锭硼,地道東北人房资。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像檀头,于是被迫代替她去往敵國和親轰异。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容