为什么你应该使用 Repository

18

原文来自http://vegibit.com/laravel-repository-pattern/

Repository 模式

为了保持代码的整洁性和可读性,使用Repository Pattern 是非常有用的。事实上,我们也不必仅仅为了使用这个特别的设计模式去使用Laravel,然而在下面的场景下,我们将使用OOP的框架Laravel 去展示如何使用repositories 使我们的Controller层不再那么啰嗦、更加解耦和易读。下面让我们更深入的研究一下。

不使用 repositories

其实使用Repositories并不是必要的,在你的应用中你完全可以不使用这个设计模式的前提下完成绝大多数的事情,然而随着时间的推移你可能把自己陷入一个死角,比如不选择使用Repositories会使你的应用测试很不容易,具体的实现将会变的很复杂,下面我们看一个例子。
HousesController.php

<?php
    class HousesController extends BaseController {
        public function index()
        {
            $houses = House::all();
            return View::make('houses.index',compact('houses'));
        }    
        
        public function create()
        {
            return View::make('houses.create');
        }
        public function show($id)
        {
            $house = House::find($id);
            return View::make('houses.show',compact('house'));
        }
    }

这是一个很典型的一段代码使用Eloquent和数据库交互,这段代码工作的很正常,但是controller层对于Eloquent而言将是紧耦合的。在此我们可以注入一个repository创建一个解耦类型的代码版本,这个解耦的版本代码可以使后续程序的具体实现更加简单。

使用 repositories

其实完成整个repository模式需要相当多的步骤,但是一旦你完成几次就会自然而然变成了一种习惯了,下面我们将详细介绍每一步。

1.创建 Repository 文件夹

首先我们需要在app文件夹创建自己Repository 文件夹repositories,然后文件夹的每一个文件都要设置相应的命名空间。

2: 创建相应的 Interface

第二步创建对应的接口,其决定着我们的repository类必须要实现的相关方法,如下例所示,在此再次强调的是命名空间一定要记得加上。
HouseRepositoryInterface.php

<?php namespace App\Repositories;

interface HouseRepositoryInterface {
    public function selectAll();
    
    public function find($id);
}

3:创建对应的 Repository

现在我们可以创建我们repository类 来给我们干活了,在这个类文件中我们可以把我们的绝大多数的数据库查询都放进去,不论多么复杂。如下面的例子
DbHouseRepository.php


<?php namespace App\Repositories;

use House;

class DbHouseRepository implements HouseRepositoryInterface {
    
    public function selectAll()
    {
        return House::all();
    }

    public function find($id)
    {
        return House::find($id);
    }
}

4:创建后端服务提供

首先你需要理解所谓服务提供,请参考手册服务提供者
BackendServiceProvider.php


<?php namespace App\Repositories;

use IlluminateSupportSeriveProvider;

class BackSerivePrivider extends ServiceProvider {

    public function register()
    {
        $this->app->bind('App\Repositories\HouseRepositoryInterface', 'App\Repositories\DbHouseRepository');
    }
}

当然你也可以新建一个文件夹主要放我们的provider相关文件。
上面一段代码主要说的是,当你在controller层使用类型提示HouseRepositoryInterface,我们知道你将会使用DbHouseRepository.

5:更新你的Providers Array

其实在上面的代码中,我们已经实现了一个依赖注入,但如果我们要使用在此我们是需要手动去写的,为了更为方面,我们需要增加这个providers 到app/config/app.php 中的 providers数组里面,只需要在最后加上App\Repositories\BackendServiceProvider::class,

6:最后使用依赖注入更新你的controller

当我们完成上面的那些内容之后,我们在Controller只需要简单的调用方法代替之前的复杂的数据库调用,如下面内容:
HousesController.php

<?php 

use App\repositories\HouseRepositoryInterface;

class HousesController extends BaseController {

    public function __construct(HouseRepositoryInterface $house)
    {
        $this->house = $house;
    }


    public function index()
    {
        $houses = $this->house->selectAll();

        return View::make('houses.index', compact('houses'));
        
    }


    public function create()
    {
        return View::make('houses.create');
    }


    public function show($id)
    {
        $house = $this->house->find($id);
        
        return View::make('houses.show', compact('house'));

    }
}

这样整个的流程就完成了。翻译的不太好,请大家见谅,做了一些改动。


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

18 条评论
苏生不惑 · 2015年12月07日

有个问题,HouseRepositoryInterface这个依赖注入是放在构造函数里还是普通函数里好呢
`public function index(HouseRepositoryInterface $house)

{
    $houses = $house->selectAll();

    return View::make('houses.index', compact('houses'));
    
}`

+1 回复

0

理论上都可以,但是实际上放到构造函数会更加合适, 因为一个控制器很多地方都会用到这个

wh469012917 · 2018年04月12日
丁一 · 2015年11月08日

太好了,最近刚学laravel不久,正在做练习,发现直接在controller里面写Eloquent ORM来操作数据库再叠加上一系列的逻辑操作简直不能看。。正在找对应的解决方案,学习了,谢谢。

回复

0
  1. 没看明白, 你是怎么用的 ?
bushiyao_ · 2017年10月12日
马海东 · 2015年11月08日

我也来学习学习 :)

回复

lx1036 · 2016年05月05日

恩恩,不能再同意了。

回复

lx1036 · 2016年05月05日

文章写得挺好的,今天刚刚看了Repository设计模式,看了这篇文章了解的更多了,虽然之前看过。

回复

rockman · 2016年10月22日

这样就是将数据库的操作封装了下,和直接写一个model封装类相比有什么优势吗?

回复

0

参考java开发中的dao和service分层

wh469012917 · 2017年04月28日
0

跟model比起来差不多,每一个repository都是一个model,只不过用接口把他们统一管理起来了,突然间有一天,这个model里面的方法想修改,但是之前的又想保留下来,那么按照对应的接口在实现一个repository就好了,实际意义呢,仁者见仁智者见智,确实在解决耦合的方面有一点优点,将Controller对repository的依赖放到接口上,更改repository的实现对Controller影响较小,用服务提供者来实现注入,新增repository需要重新更改绑定,每次只提供一个repository,实质和model一样,意义不大。

sowork · 2017年09月04日
0

当你不使用服务提供者,不绑定repository,那就失去了注入的优点,同时也解决不了耦合问题,既然没有注入的优点,调用的时候势必要进行实例化,,,,何来的解决耦合

sowork · 2017年09月04日
stoneworld 作者 · 2016年10月22日

分层,解耦,方便单元测试等等

回复

0

能不能举个例子说明优点,代码是看懂了,但看不出优点

水到渠成 · 2017年03月31日
0

同上

会游泳的猫猫 · 2017年05月31日
Grocker · 2018年07月12日

不错,刚来公司看到项目有用这个设计模式,里面全是数据库相关的操作,看了这篇文章加深了理解,3Q

回复

黄天翔 · 2018年08月07日

没明白,为什么需要 创建后端服务提供 这一步骤?

回复

aaaa · 2018年09月14日

麻烦问下是不是还缺少service层,逻辑要写哪里 是写控制器吗

回复

0

是的 需要service层 大多是service层是处理业务逻辑层调用相关repository,而repository层更多是model之间的调用封装,而controller层是接收参数调用的更多是service层,当然也可以直接调用repository层

stoneworld 作者 · 2018年09月16日
载入中...