初學(xué)者學(xué)習(xí)Laravel時(shí)分兩種,一種是乖乖的將程序填入MVC構(gòu)架內(nèi),導(dǎo)致controller與model異常的肥大,日后一樣很難維護(hù);一種是常常不知道程序該寫(xiě)在哪一個(gè)class內(nèi)而猶豫不決,畢竟傳統(tǒng)PHP都是一個(gè)頁(yè)面一個(gè)檔案。本文整理出最適合Laravel的中大型項(xiàng)目構(gòu)架,兼具容易維護(hù)、容易擴(kuò)充與容易重復(fù)使用的特點(diǎn),并且容易測(cè)試。
受RoR的影響,初學(xué)者常認(rèn)為MVC構(gòu)架就是model,view,controller:
Model就是數(shù)據(jù)庫(kù)。
Controller負(fù)責(zé)與HTTP溝通,調(diào)用model與view。
View就是HTML。
假如依照這個(gè)定義,以下這些需求該寫(xiě)在哪里呢?
發(fā)送Email,使用外部API。
使用PHP寫(xiě)的邏輯。
依需求將顯示格式作轉(zhuǎn)換。
依需求是否顯示某些數(shù)據(jù)。
依需求顯示不同數(shù)據(jù)。
其中1,2屬于商業(yè)邏輯,而3,4,5屬于顯示邏輯,若依照一般人對(duì)MVC的定義,model是數(shù)據(jù)庫(kù),而view又是HTML,以上這些需求都不能寫(xiě)在model與view,只能勉強(qiáng)寫(xiě)在controller。
因此初學(xué)者開(kāi)始將大量程序?qū)懺赾ontroller,造成controller的肥大難以維護(hù)。
既然邏輯寫(xiě)在controller不方便維護(hù),那我將邏輯都寫(xiě)在model就好了?
當(dāng)你將邏輯從controller搬到model后,雖然controller變瘦了,但卻肥了model,model從原本代表數(shù)據(jù)庫(kù),現(xiàn)在變成還要負(fù)擔(dān)商業(yè)邏輯與顯示邏輯,結(jié)果更慘。
Model代表數(shù)據(jù)庫(kù)嗎?把它想成是Eloquent class就好,數(shù)據(jù)庫(kù)邏輯應(yīng)該寫(xiě)在repository里,這也是為什么Laravel 5已經(jīng)沒(méi)有models目錄,Eloquent class僅僅是放在app根目錄下而已。
那我們?cè)撛趺磳?xiě)呢?別將我們的思維局限在MVC內(nèi):
Model:僅當(dāng)成Eloquent class。
Repository:輔助model,處理數(shù)據(jù)庫(kù)邏輯,然后注入到service。
Service:輔助controller,處理商業(yè)邏輯,然后注入到controller。
Controller:接收HTTP request,調(diào)用其他service。
Presenter:處理顯示邏輯,然后注入到view。
View:使用blade將數(shù)據(jù)binding到HTML。
我們將數(shù)據(jù)庫(kù)邏輯從model分離出來(lái),由repository輔助model,將model依賴注入進(jìn)repository。
我們將商業(yè)邏輯從controller分離出來(lái),由service輔助controller,將service依賴注入進(jìn)controller。
我們將顯示邏輯從view分離出來(lái),由presenter輔助view,將presenter依賴注入進(jìn)view。
在 app 目錄建立 Repositories,Services 與 Presenters 目錄。
Repository
由于篇幅的關(guān)系,將repository獨(dú)立成專文討論,請(qǐng)參考如何使用Repository模式?
Service
由于篇幅的關(guān)系,將service獨(dú)立成專文討論,請(qǐng)參考如何使用Service模式?
Presenter
由于篇幅的關(guān)系,將presenter獨(dú)立成專文討論,請(qǐng)參考如何使用Presenter模式?
單元測(cè)試
由于現(xiàn)在model、view、controller的相依物件都已經(jīng)拆開(kāi),也都使用依賴注入,因此每個(gè)部分都可以單獨(dú)的做單元測(cè)試,如要測(cè)試service,就將repository加以mock,也可以將其他service加以mock。
Presenter也可以單獨(dú)跑單元測(cè)試,將其他service加以mock,不一定要跑驗(yàn)收測(cè)試才能測(cè)顯示邏輯。
本文談到的構(gòu)架只是開(kāi)始,你可以依照實(shí)際需求增加更多的目錄與class,當(dāng)你發(fā)現(xiàn)你的MVC違反SOLID原則時(shí),就大膽的將class從MVC拆開(kāi)重構(gòu),然后依照以下手法:
建立新的class或interface。
將相依物件依賴注入到class。
在class內(nèi)處理他的職責(zé)。
將class或interface注入到controller或view。
最后搭配單元測(cè)試,測(cè)試重構(gòu)后的構(gòu)架是否與原來(lái)的需求結(jié)果相同。
聯(lián)系客服