如何更优雅的给控制器 “减负”

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

相关文章
相关标签/搜索