如何在laravel中使用Repository Pattern(仓库模式)

24 篇文章 1 订阅

来,这样做的好处有以下几点:

  1. 把数据处理逻辑分离使得代码更容易维护
  2. 数据处理逻辑和业务逻辑分离,可以对这两个代码分别进行测试
  3. 减少代码重复
  4. 降低代码出错的几率
  5. 让 controller 代码的可读性大大提高

如图所示 Repository 的分层关系

 

图片

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

学习 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
├── Implements
├── Interfaces
└── Repositories

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

第二步 建立一个接口

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

<?php
namespace App\Repositories\Interfaces;

interface PostInterface{
   public function findPosts(array $cat_id, $is_draft, $order, $take)
   {

   }
}

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

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

<?php
namespace App\Repositories\Implements;
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();

        return $query;
    }
}

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

第四步 在 ServiceProvider 中绑定接口

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

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        //
    }

    public function register()
    {
        $this->app->bind('App\Repositories\Interfaces\PostInterface', 'App\Repositories\Implements\PostRepository');
    }
}

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

第五步 使用仓库

回到我们的 controller 里来

<?php
use App\Repositories\Interfaces\PostInterface;

class PostController extends BaseController{

    public function __construct(PostInterface $post){
        $this->postRepo = $post;
    }

    public function index(){
        $this->postRepo->findPosts([1, 2], 0, 'desc' ,5);
    }
}

从上面的例子看,我们的业务逻辑变得非常精简,完全不用管查询;而且也现实了数据查询部分的解耦;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值