Laravel 的中大型专案架构

 只有MVC 是不够的,我们需要更完整的专案架构

初学者学习Laravel时分两种,一种是乖乖的将程式填入MVC架构内,导致controller与model异常的肥大,日后一样很难维护;一种是常常不知道程式该写在哪一个class内而犹豫不决,毕竟传统PHP都是一个页面一个档案。本文整理出最适合Laravel的中大型专案架构,兼具容易维护容易扩充容易重复使用的特点,并且容易测试

Version


Laravel 5.1.24

Controller 过于肥大


受RoR的影响,初学者常认为MVC架构就是modelviewcontroller:

  • Model 就是资料库。
  • Controller 负责与HTTP 沟通,调用model 与view。
  • View 就是HTML。

假如依照这个定义,以下这些需求该写在哪里呢?

  1. 发送Email,使用外部API。
  2. 使用PHP 写的逻辑。
  3. 依需求将显示格式作转换。
  4. 依需求是否显示某些资料。
  5. 依需求显示不同资料。

其中1, 2 属于商业逻辑,而3, 4, 5 属于显示逻辑,若依照一般人对MVC 的定义,model 是资料库,而view 又是HTML,以上这些需求都不能写在model 与view,只能勉强写在controller。

因此初学者开始将大量程式写在controller,造成controller 的肥大难以维护。

Model 过于肥大


 既然逻辑写在controller 不方便维护,那我将逻辑都写在model 就好了?

当你将逻辑从controller 搬到model 后,虽然controller 变瘦了,但却肥了model,model 从原本代表资料库,现在变成还要负担商业逻辑与显示逻辑,结果更惨。

Model代表资料库吗?把它想成是Eloquent class就好,资料库逻辑应该写在repository里,这也是为什么Laravel 5已经没有models目录,Eloquent class仅仅是放在app根目录下而已。

中大型专案架构


那我们该怎么写呢?别将我们的思维局限在MVC 内 :

  1. Model :仅当成Eloquent class。
  2. Repository :辅助model,处理资料库逻辑,然后注入到service。
  3. Service :辅助controller,处理商业逻辑,然后注入到controller。
  4. Controller :接收HTTP request,调用其他service。
  5. Presenter :处理显示逻辑,然后注入到view。
  6. View :使用blade将资料binding到HTML。

其中蓝色为原本的MVC,而紫色为本文要介绍的的重点: Repository模式,Service模式与Presenter模式。

箭头表示物件依赖注入的方向。11关于依赖注入,详细请参考深入探讨依赖注入

我们可以发现MVC架构还在,由于SOLID单一职责原则与依赖反转原则:

  1. 我们将资料库逻辑从model 分离出来,由repository 辅助model,将model 依赖注入进repository。
  2. 我们将商业逻辑从controller 分离出来,由service 辅助controller,将service 依赖注入进controller。
  3. 我们将显示逻辑从view 分离出来,由presenter 辅助view,将presenter 依赖注入进view。

建立目录

app目录下建立RepositoriesServicesPresenters目录。

 别害怕建立目录!!

别害怕在Laravel预设目录以外建立的其他目录,根据SOLID单一职责原则,class功能越多,责任也越多,因此越违反单一职责原则,所以你应该将你的程式分割成更小的部分,每个部分都有它专属的功能,而不是一个class功能包山包海,也就是所谓的万能类别,所以整个专案不应该只有MVC三个部分,放手根据你的需求建立适当的目录,并将适当的class放到该目录下,只要我们的class有namespace帮我们分类即可。

Repository

由于篇幅的关系,将repository独立成专文讨论,请参考如何使用Repository模式?

Service

由于篇幅的关系,将service独立成专文讨论,请参考如何使用Service模式?

Presenter

由于篇幅的关系,将presenter独立成专文讨论,请参考如何使用Presenter模式?

单元测试


由于现在model、view、controller 的相依物件都已经拆开,也都使用依赖注入,因此每个部分都可以单独的做单元测试,如要测试service,就将repository 加以mock,也可以将其他service 加以mock。

Presenter 也可以单独跑单元测试,将其他service 加以mock,不一定要跑验收测试才能测显示逻辑。

Conclusion


  • 本文谈到的架构只是开始,你可以依照实际需求增加更多的目录与class,当你发现你的MVC违反SOLID原则时,就大胆的将class从MVC拆开重构,然后依照以下手法:

    1. 建立新的class 或interface。
    2. 将相依物件依赖注入到class。
    3. 在class 内处理他的职责。
    4. 将class 或interface 注入到controller 或view。
  • 最后搭配单元测试,测试重构后的架构是否与原来的需求结果相同。

 

转载自:https://oomusou.io/laravel/architecture/

猜你喜欢

转载自blog.csdn.net/qw_xingzhe/article/details/83215679