如何更優雅的給控制器 「減負」

MVC是一個很是偉大的概念,可是最近我發現一個現象,包括我本身,咱們在最開始接觸MVC概念時,咱們很是嚴謹地貫徹這種分層思想,Controller層處理業務邏輯,而Model層只是單純的處理數據I/O。可是,伴隨着咱們項目體量的逐漸增大,控制器的負擔也愈來愈大。這樣一來會有一個很是明顯的弊端,當咱們在定位BUG時,咱們老是須要對照着代碼查看許久。除此以外,彼此的業務代碼並無太好的關聯,這使得咱們想要抽出一個Service時就顯得極爲困難。
所以,是時候給咱們的控制器作一些「減負」了。這裏的減負並不意味着會違背MVC的設計思想,而是把咱們的控制器層的業務適當的分給其餘部分。
有使用過一些主流框架的朋友應該都知道,其實不少框架都給Controller層作了一些「減負」的工做,好比KOA裏面的middleware,抑或是Laravel裏面的Event,Policy等。
可是事與願違,即便這些框架提供了這些幫助,可是許多人在實際項目中使用到的卻不多,固然,也有多是我接觸到的代碼不夠多。究其緣由,竊覺得還沒有意識到這種理念的重要性。所以,我在這裏總結了本身這些年來「減負」的一些經驗,同時我也會配合一些代碼予以解釋。固然,我所寫的未必全對,所以但願有幸看到的讀者能保持本身的獨立性。php

Model分流

咱們在寫代碼時每每會有這樣一種場景,咱們須要對從Model取出來的數據進行加工,可是,加工數據的部分咱們常常會放到控制器,畢竟這屬於業務邏輯,確實無可厚非,以下僞代碼所示:數據庫

// controller
public function userList()
{
    $users = array_map(function ($user){
//        這裏會對咱們的代碼進行業務邏輯的加工
        $user['created_at'] = date('Y-m-d' , $user['created_at']);
        // ...
        return $user;
    } ,$model->availableList());
}

// model
public function availableList()
{
    // 從數據庫取數據  
    return $users;
}

可是咱們有沒有考慮過這樣一個問題,當咱們同事來接手咱們項目或者咱們debug時,咱們須要瞭解的代碼量很是大,特別是涉及到一些數據加工的格式問題,咱們並不須要關心。或者換個角度,當咱們遇到數據加工的bug時,咱們能第一聯想到這段代碼是放在Model層時,是否是更加快捷呢?框架

// controller
public function userList()
{
    $users = $model->availableList();
//    處理其餘邏輯
}

// model
public function availableList()
{
    // 從數據庫取數據 $users
    return array_map(function ($user){
//        這裏會對咱們的代碼進行業務邏輯的加工
        $user['created_at'] = date('Y-m-d' , $user['created_at']);
        // ...
        return $user;
    } , $users);
}

如上代碼所示,在Model層中已經幫咱們封裝好了咱們所須要的數據以及其格式,當咱們在瀏覽他人代碼時,咱們並不須要關心他的格式是怎麼加工的,咱們只須要根據他對方法的命名就能知道是獲取的怎樣的數據。網站

分離Controller

在寫具體的方法以前,我想要闡述的一點是,咱們在寫代碼的時候須要保持必定的前瞻性。什麼意思?雖然咱們的大部分工做都是跟具體的業務邏輯打交道,可是咱們常常會發現總會有重複的工做,那麼有的人會直接把這段代碼複製。可是,在咱們複製以前,咱們是否是能夠問本身這樣一個問題:若是接下來還有相似的業務,咱們仍是複製嗎?咱們是否是能夠把這段基於咱們項目的代碼抽象出一個Service呢?
我舉個例子,好比一個網站,可能會有打賞功能,可能也有付費閱讀功能,咱們不難發現,這兩種付費有着類似的地方,好比建立本平臺訂單系統的業務邏輯,再好比回掉時可能存在的相同業務邏輯,因此這段代碼咱們是否是能夠以一個trait的形式作一個Servicethis

trait PayService
{
    private $_callback = null;

    public function createOrder()
    {
//        處理你的業務邏輯,配置調用三方支付接口的參數等
    }

    public function callback()
    {
//        處理共同的回調邏輯
        
        $this->handler();
    }
}

這裏咱們保留了一個handler方法來處理每一個功能獨有的業務邏輯,至此,咱們就能夠很是方便的擴展咱們的支付服務了。debug

給控制器減負的方法還有不少,好比對咱們加工數據的部分,其實咱們也能夠不放到Model,咱們也能夠單獨開闢一層來處理咱們的數據加工。讓控制器變得清晰明朗,每一個人閱讀代碼時都能很是快速的瞭解控制器下的每一個方法在處理什麼業務邏輯。這即是咱們給控制器減負的目的。
我很喜歡「包」的概念和設計思想,當咱們在使用包時,不只僅意味着方便,更重要的是,他作爲一個獨立的「組件」存在於咱們的代碼邏輯中,與咱們項目的代碼不存在任何的耦合,同時咱們也無需知道他的具體實現。設計

文章首發地址:個人博客code

相關文章
相關標籤/搜索