Laravel与Repository Pattern(仓库模式)——概念篇

来源:互联网 发布:网络剧营销创意 编辑:程序博客网 时间:2024/06/06 07:20

为什么要学习Repository Pattern(仓库模式)

Repository 模式主要思想是建立一个数据操作代理层,把controller里的数据操作剥离出来,这样做有几个好处:

  • 把数据处理逻辑分离使得代码更容易维护

  • 数据处理逻辑和业务逻辑分离,可以对这两个代码分别进行测试

  • 减少代码重复

  • 降低代码出错的几率

  • 让controller代码的可读性大大提高

然而,据很多同学反应,这一部分很难学。确实,要独立一个操作层出来,确实会增加大量代码,非常繁琐。如果你是小项目,未必需要使用这一模式。但如果是4-5年以上的复杂大型项目,这种模式的好处就比较明显了。

如果你是纯新手,建议你暂时不要往下看,先把laravel用得比较熟练后再回来学习。

学习Repository Pattern的意义不只是为了使用它,更会让你深入思考框架的分层思想,你开始不仅关注怎么使用一个框架,还会想了解怎样设计一个框架,也许会成为你往高阶段编程的入口。

什么是Repository Pattern

虽然说设计模式和语言及框架无关,但是脱离了语言及框架,我们很难理解,所以我们还是在laravel的语境下来学习吧:

public function index(){ $posts = Post::whereIn('category_id',[1,2])->where('is_draft',0)->orderBy('created_at', 'desc')->take(5)->get(); return view('front.index',compact('posts'));}

以上是典型的Eloquent数据查询代码,如果你编程经验丰富,你会发现这种代码在控制器里到处都是,而且有很多是重复的,可读性很差;我们的目标是把它精简:

仔细观察

Post::whereIn('category_id',[1,2])->where('is_draft',0)->orderBy('created_at', 'desc')->take(5)->get();

其实它由3部分组成,第一是Post,数据模型;第二个是whereIn('category_id',[1,2])->where('is_draft',0)->orderBy('created_at', 'desc')->take(5),数据操作条件;第三个是get(),数据获取的方法;

我们知道,Eloquent里有个Query Scope,可以用来把第二部分,也就是查询条件精简。所以,在使用了Query Scope后,我们可以把精简成:

Post::ofCategory([1,2])->isDraft()->orderBy('created_at', 'desc')->take(5)->get();

咋一看上去,好像也没怎么精简啊,但实际上你已经实现代码解耦和复用了,比如说isDraft(), 这个代码可以到处用,而不用担心耦合问题。

精简程度和你的逻辑抽象程度有关,比如说你完全可以写成:

Post::findPosts([1,2],0,'desc',5)->get();

在轻型项目中,强烈推荐使用Query Scope,这是一种良好的编程习惯。

在更复杂的项目中,Query Scope就不够用了,因为它和数据模型还是一种强耦合,Repository Pattern就是要把第一,第二,第三部分全部解耦;

说到解耦,我们在Laravel的文档攻略中讲过,第一神器就是PHP中的接口(Interface),下面来看例子:

第一步——建立文件夹

  • app

    • Repositories

      • Interfaces

      • Implements

Interfaces里面用来放接口,Implements用来放接口的实现;

第二步——建立一个接口

在上面的Interfaces目录新建一个文件PostInterface.php:

namespace AppRepositoriesInterfaces;Interface PostInterface{ public function findPosts(Array $cat_id,$is_draft,$order,$take){}}

第三步——建立一个接口对应的实现

在上面的Implements目录新建一个文件PostRepository.php:

namespace AppRepositoriesImplements;use Post;class PostRepository Implements PostInterface{ public function findPosts(Array $cat_id,$is_draft,$order,$take){ $query = Post::whereIn('category_id',$cat_id)->where('is_draft',$is_draft)->orderBy('created_at', $order)->take($take)->get();}}

看这里,很明显,仓库指的就是一个仓库接口的实现;这里定义你的业务逻辑;

第四步——在ServiceProvider中绑定接口

打开app/Providers/AppServiceProvider, 在register()加入代码:

<?phpnamespace AppProviders;use IlluminateSupportServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot(){} public function register(){ $this->app->bind('AppRepositoriesInterfacesPostInterface', 'AppRepositoriesImplementsPostRepository');}}

我们知道,ServiceProvider是Laravel IOC容器实现动态换接口实现的地方,所以我们在这里绑定一下,这样我们在使用的时候,不直接使用接口实现,而是用ioc容器解析接口,它会帮你自动找到对应好的实现。 这就意味着,以后需要更换实现,可以在这里更换;

第四步——使用仓库

回到我们的controller里来:

use AppRepositoriesInterfacesPostInterface;class PostController extends BaseController{ public function __construct(PostInterface $post){ $this->postRepo = $post;} public function index(){$this->postRepo->findPosts([1,2],0,'desc',5);}}

这样你看,第一,我们的业务逻辑变得非常精简,完全不用管查询;第二,现实了数据查询部分的解耦;

到这里,有同学就会问了,一开始说好的三个部分解耦呢,你这里只实现了第二部分啊;

确实,为了最快让大家明白什么是Repository,我把第一和第二部分的解耦省略了,我们放到这篇文章的系列后续讲。

你或许还有不少疑惑,我费那么大劲,写成最后这个样子,好像也没什么区别啊。聪明的同学可能想到一点,如果采用Repository Pattern的话,是不是意味着以后我可以先在controller里写成$this->postRepo->findPosts([1,2],0,'desc',5); 具体的查询逻辑先不写,然后我快速先把 整个应用的业务逻辑先跑一遍,然后再回头一个一个写接口实现来支持业务逻辑;(哇擦,太NB了,妈妈再也不用担心SB客户/PM改变需求了);

恭喜,你已经进入高级编程里说的DDD(Domain Driven Design 领域驱动设计)大门了,事实上,整个Laravel框架的核心架构就是这样干的,IOC+接口,我们会在后续系列文章里介绍;

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一周多宝宝吐怎么办 反复呕吐一晚上怎么办 两岁婴幼儿呕吐怎么办 婴幼儿喂药呕吐怎么办 九个月婴儿呕吐怎么办 宝宝半夜咳嗽吐怎么办 小孩晚上咳嗽吐怎么办 小孩发烧手脚热怎么办 孩子发烧了呕吐怎么办 宝宝高烧后呕吐怎么办 孩子发烧39呕吐怎么办 发烧反胃想吐怎么办 孩子发烧一直吐怎么办 宝宝发烧一直吐怎么办 小孩发烧一直吐怎么办 小孩子发烧一直吐怎么办 孩子吐还拉稀怎么办 宝贝拉肚子又吐怎么办 小孩子发烧呕吐拉肚子怎么办 小孩受凉呕吐拉肚子怎么办 一周岁宝宝发烧怎么办 宝宝吃了吐怎么办 儿子喝水都吐怎么办 宝宝吐奶拉肚子怎么办 怀孕吐的厉害怎么办 孩子一直呕吐怎么办啊 仓鼠宝宝拉稀了怎么办 2岁有点拉稀怎么办 婴儿吃米粉腹泻怎么办 小儿胃寒呕吐怎么办 孩子突然一直吐怎么办 宝宝呕吐并发烧怎么办 宝宝发烧呕吐拉稀怎么办 小孩发高烧还吐怎么办 二个多月的宝宝拉肚子怎么办 宝宝肚子着凉吐怎么办 孩子胃着凉呕吐怎么办 一岁受凉呕吐怎么办 孩子着凉了呕吐怎么办 小孩受凉呕吐腹泻怎么办 宝宝胃受寒呕吐怎么办