為什麼要分層?
適度的分層可以幫助我們整理、歸類程式,維持程式庫的整潔性,除了方便我們管理程式,日後團隊協作時,也可以以依照層級劃分工作,促進團隊開發效率,也能降低溝通成本。
如何分層?
Service層(商業邏輯層)
通常程式可以被粗略地分成兩種,商業邏輯跟非商業邏輯的部分。
商業邏輯其實就是這個系統被創造的原因,我們利用程式、串連各種系統資源,讓資料變更或流向我們想要的地方,來促進商業行為的發生。
但是這樣的商業邏輯程式碼,如果沒有經過整理,將會非常雜亂。
有些人會把所有商業邏輯都寫在Model中,有些人則會寫在Controller。
寫在Model中的缺點是,Model處理的事情過多,若以訂單Model為例,包含成立訂單、取消訂單、修改訂單及其相關的細節,都要在訂單Model中處理的話,Model會長成巨無霸。
如果都在Controller中處理,則程式碼則會零散在各個Controller,一定會有部分邏輯處理是相通的,卻無法重複使用。
因此可以把商業邏輯獨立出來變成Service層。
將商業邏輯都集中在Service層中,Controller中可以直接呼叫Service,來處理商業邏輯。
而Service則再透過Model來對DB做操作。
對Controller來說,產生訂單會變成類似這樣的用法:
$createOrderService->createOrder($orderData);
當今天有複數以上的Controller也要產生訂單,只要在Controller也使用同樣的Service即可。或是如同文章一開始所展示的圖片,自訂的Command,也可以使用Service所提供的function,來完成指令。
Repository層
Repository層主要的用途是集中管理取得與更新資料的部分。
雖然Laravel Model可以讓你很輕鬆地組出SQL去取得或更新資料,但若隨著系統成長,這樣的程式零散在各地,即便是零散在前面所說的Service中,都會造成管理上跟維護上的困擾。
如果我們將Respository層分出來,實際上的用法大概會像這樣:
$order = $orderRepository->get($orderId);
...
$orderRepository->add($order);
將原本在Controller或是Service中直接透過model去跟DB做互動的程式,通通放置到Repository之中。
而除了整理程式以外,Repository還有兩個用途:
- SQL, Database這些東西,其實算是實作上的細節,如果我們將這些東西抽離出主要商業邏輯程式,可以降低主要程式跟資料庫(也就是外部系統)的相依性。
- 比較方便進行單元測試,可以更容易注入mock後的repository。
分層後概況
以Laravel 5.8為例,分層後的目錄結構大概會長這樣。
app
│
└───Models
│ │ OrderModel
│
└──-Repositories
│ │ OrderRepository
│
└───Services
│ │ CreateOrderService
│ │ CancelOrderService
│
└───Http/Controllers
│ │ OrderController
總結
這個簡單的分層方式,對於一般中小型專案應該足夠使用了。但不會有一個架構可以符合所有的需求,還是要視情況調整。