摘要:确实,要独立一个操作层出来,确实会增加大量代码,非常繁琐。如果你是小项目,未必需要使用这一模式。但如果是年以上的复杂大型项目,这种模式的好处就比较明显了。如果你是纯新手,建议你暂时不要往下看,先把用得比较熟练后再回来学习。
为什么要学习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() 加入代码:
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+接口,我们会在后续系列文章里介绍;
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/21511.html
摘要:按照最初提出者的介绍,是衔接数据映射层和领域层之间的一个纽带,作用相当于一个在内存中的域对象集合。客户端对象把查询的一些实体进行组合,并把它们提交给。同时支持登录过期时间设置,登录之前,登录之后事件处理。 laravel 开发辅助工具 配置 添加服务提供商 将下面这行添加至 config/app.php 文件 providers 数组中: providers => [ ... ...
摘要:但在中也不可避免的基础模式,上述问题仍然存在。这样可以完全分离和的依赖。最开始在中使用是通过定义大量的来注入,,实现具体的工作类。但是像链接调用仍然没有解决,为些我们开发出了新的仓库包。目前此包已经使用在好几个项目中目前运行良好。 什么是Repository模式,如何使用Repository模式 这里就不再啰嗦了,请参见以下几个链接如何使用 Repository 模式?关于 Repos...
摘要:原文来自模式为了保持代码的整洁性和可读性,使用是非常有用的。这是一个很典型的一段代码使用和数据库交互,这段代码工作的很正常,但是层对于而言将是紧耦合的。 原文来自http://vegibit.com/laravel-repository-pattern/ Repository 模式 为了保持代码的整洁性和可读性,使用Repository Pattern 是非常有用的。事实上,我们也不必...
摘要:业务层,业务层,是最为核心的一层。对于和的状态保存恢复也通过处理。对于的绑定操作和命令操作都是暴露的,也易于测试。需要注意的是标签的节点中要使用到根节点中标签里设置的的话需要这样设置抽象类中设置了和注解,只起到清晰提醒作用。 原文发表于:Rockos blog(rocko.xyz)] - MVVM_Android-CleanArchitecture 前言 Architecture is...
阅读 2161·2023-04-26 00:43
阅读 2680·2021-11-22 15:22
阅读 3808·2021-11-11 16:55
阅读 965·2021-11-04 16:06
阅读 1781·2019-08-30 14:12
阅读 993·2019-08-30 14:02
阅读 3365·2019-08-29 17:05
阅读 1414·2019-08-29 12:27