代碼分層設(shè)計(jì)實(shí)踐與總結(jié)
簡(jiǎn)介
見過很多PHP開發(fā)者的代碼,在代碼分層上面都不是很注重。一般都是控制器負(fù)責(zé)所有的業(yè)務(wù)邏輯,在控制器中調(diào)用模型做數(shù)據(jù)操作、驗(yàn)證數(shù)據(jù)也在控制器中等等情況。這樣的做法怎么說呢?也沒錯(cuò),但是這樣寫代碼就顯示的很雜糅。
本文分享一些個(gè)人的代碼分層想法,存在不足的地方,希望大家多多提出一些寶貴建議。
文章底部有代碼示例連接,可以直接通過代碼查看或許更加方便。
相關(guān)技術(shù)
Laravel資源控制器、Laravel模型、PHP對(duì)象接口
實(shí)現(xiàn)思路
大致實(shí)現(xiàn)的思路如下:
// uml圖
@startuml
controller->service:調(diào)用
service->repository:調(diào)用
repository->model:調(diào)用
@enduml
controller層直接調(diào)用service層,controller主要負(fù)責(zé)傳遞請(qǐng)求參數(shù),返回接口數(shù)據(jù)。 service層負(fù)責(zé)處理數(shù)據(jù)邏輯,將controller接收到的參數(shù)格式化,然后將整理好的數(shù)據(jù)傳遞給repository層。 repository層直接調(diào)用model層的示例,進(jìn)行數(shù)據(jù)操作。 model層主要責(zé)任是映射數(shù)據(jù)表,定義一個(gè)有關(guān)數(shù)據(jù)表的操作。例如表名、時(shí)間錯(cuò)、獲取器和修改器等等。
代碼演示
首先定義了如下的目錄結(jié)構(gòu),具體的其他結(jié)構(gòu)可以根據(jù)自己的需要來定義,例如驗(yàn)證層、接口響應(yīng)層、資源層等等。
為了保證在controller、service、repository層中的相關(guān)方法名稱以及返回參數(shù)格式都保持一致,在每一個(gè)層,都定義一個(gè)接口,接口中的方法都定義好參數(shù)格式以及返回值類型。例如controller層。首先我們定義一個(gè)controller層接口.
<?php
namespace App\Http\Controllers;
/**
* Api controller service
*
* Interface ApiServiceController
* @package App\Http\Controllers
*/
interface ApiServiceController
{
/**
* 具體每個(gè)方法的定義參考laravel文檔
* https://learnku.com/docs/laravel/5.8/controllers/3893#resource-controllers
*/
public function index();
public function create();
public function store();
public function show();
public function edit();
public function update();
public function destroy();
}
對(duì)應(yīng)的實(shí)現(xiàn)類controller,實(shí)現(xiàn)ApiServiceController接口。
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\ApiAuthBaseController;
use App\Http\Controllers\ApiServiceController;
use App\Services\UserInterface;
/**
* User's controller
*
* Class UserController
* @package App\Http\Controllers\User
*/
class UserController extends ApiAuthBaseController implements ApiServiceController
{
public function __construct(UserInterface $apiService)
{
$this->service = $apiService;
parent::__construct($apiService);
}
public function index()
{
$items = $this->service->serviceIndex((array)$this->requestParams);
return response()->json([
'code' => 10001,
'msg' => 'select success',
'data' => $items,
]);
}
public function create()
{
// TODO: Implement create() method.
}
public function store()
{
if ($this->service->serviceStore((array)$this->requestParams)) {
return response()->json([
'code' => 10001,
'msg' => 'create success',
'data' => [
'id' => 1,
],
]);
}
}
public function show()
{
// TODO: Implement show() method.
}
public function edit()
{
// TODO: Implement edit() method.
}
public function update()
{
if ($this->service->serviceUpdate((array)$this->requestParams)) {
return response()->json([
'code' => 10001,
'msg' => 'update success',
'data' => [
],
]);
}
}
public function destroy()
{
if ($this->service->serviceDestroy($this->requestParams)) {
return response()->json([
'code' => 10001,
'msg' => 'delete success',
'data' => [
],
]);
}
}
}
對(duì)應(yīng)的service層、repository層都根據(jù)類似的方式定義。具體的實(shí)現(xiàn)方法可以參考文章底部的代碼示例。
接口調(diào)用演示
根據(jù)上面的代碼演示邏輯,假設(shè)我們定義好了service層和repository層對(duì)應(yīng)的邏輯,這時(shí)候我們Api添加一個(gè)資源路由的定義就可以直接調(diào)用啦。在api.php路由文件定義如下格式:
<?php
use Illuminate\Support\Facades\Route;
Route::resource('user', 'User\UserController');
接下來,我們查看一下調(diào)用結(jié)果。1.增加數(shù)據(jù)。
2.刪除數(shù)據(jù)。
3.修改數(shù)據(jù)。
4.查詢數(shù)據(jù)。
總結(jié)
本文總結(jié)只是屬于個(gè)人的一些總結(jié),存在不足的地方,歡迎大家指正。這里總結(jié)一下設(shè)計(jì)這一的思路。
使用資源路由,我們直接定義一個(gè)路由規(guī)則,增刪改查等接口方式,我們就自動(dòng)實(shí)現(xiàn)并且能夠規(guī)范團(tuán)隊(duì)中的接口,同時(shí)也符合RESTful API的規(guī)范。
使用接口定義一些業(yè)務(wù)邏輯函數(shù),實(shí)現(xiàn)類直接實(shí)現(xiàn)接口中的方法,這樣可以避免團(tuán)隊(duì)方法定義不一致、接口參數(shù)不一致、返回參數(shù)不一致等情況。如果接口中方法沒有定義,然而業(yè)務(wù)邏輯需要單獨(dú)一個(gè)方法,可以直接在實(shí)現(xiàn)類中定義獨(dú)有的方法即可。
model層主要實(shí)現(xiàn)表映射關(guān)系,這里直接把表當(dāng)做模型。因此所有的邏輯不應(yīng)該在模型層中處理,頂多定義一個(gè)屬性等情況。repository層直接去調(diào)用model層,不需要處理數(shù)據(jù)格式等情況,根據(jù)service層傳遞的條件,將查詢的數(shù)據(jù)直接返回給service層。service層則是負(fù)責(zé)業(yè)務(wù)邏輯處理,比如格式化接口請(qǐng)求參數(shù)、組裝查詢條件、刪除條件等情況。controller則是負(fù)責(zé)將請(qǐng)求的參數(shù)傳遞給service層,然后將service層返回的數(shù)據(jù)返回給客戶端。這樣每一層負(fù)責(zé)的職能獨(dú)立,互補(bǔ)關(guān)聯(lián)。降低了代碼的耦合度。
使用資源路由,簡(jiǎn)化接口。
示例代碼
代碼地址https://gitee.com/bruce_qiq/laravel-design
閱讀推薦
如何正確設(shè)計(jì)一個(gè)訂單號(hào)???
