2017-10-20 31 views
1

我只想弄清楚我是否想使用存储库模式。 的三大优势,我能找到:laravel放置模型而不是存储库的抽象

1. Testability (repositories can be injected into the controller) 
2. Abstraction (complex eloquent queries can be refactored into repository functions) 
3. Decoupling (enables me to replace the persistence layer) 

然而,除了3点我实在不明白它清楚。

1. I can just as well inject the model (or a mock for testing) 
2. I can also abstract the queries into functions and place them into the model instead of a repository. 

因此,假设我不关心与雄辩有关系,我真的没有看到使用知识库的观点。我很欣赏任何改变主意的论点。

+1

如果您使用Eloquent,我建议您将所有数据相关逻辑放入模型中。如果你这样做,你仍然遵循存储库模式,并使用存储库包有太多的缺点,并没有给你任何真正重要的优势。如果您使用的是查询生成器或原始SQL查询,请使用存储库包。 –

+0

Repository模式将帮助您将ORM作为一个整体进行替换,并使用其他一些OM,如Doctrine。如果您通过注入雄辩模型类来创建存储库,将来可以用一些其他ORM替换雄辩的ORM。但是,如果你只是想把雄辩分解成一个额外的抽象,那么它就毫无价值,而只是一种抽象。 – webDev

回答

0

从我的观点和经验来看,您可以使用Eloquent作为您的存储库层。

对于点2,您可以创建范围的方法,以便能够与正常雄辩一起使用查询

$users = User::whereHasACarOfColor('yellow')->where('active, true)->get(); 
// ... 
public function scopeWhereHasACarOfColor($query, $color) 
{ 
    return $this->whereHas(function ($cars) use ($color) { 

     return $cars->where('color', $color); 

    }); 
} 

我曾与库层的不同经验Laravel在过去的几个月:

  1. 由于我想重新使用代码,我不得不创建很多类似的方法,getUsersWithYellowCars()getUsersWithYellowCarsOrderedByName() ...
  2. 如果您决定不创建这么多特定方法,那么您将结束与一堆方法有很多的参数

    public function getUsersWithCars($color, $orderBy, $orderDescOrAsc, $paginate...) 
    
  3. 有时你需要的模型传递到仓库,而不是与他们进行互动,直接与它交互的

    $students = $usersRepository->getStudentsForProfessor($professor, 'name', 'ASC'); 
    

    代替

    $students = $professor->getStudents()->orderBy('name')->get(); 
    
  4. 一段时间后如预期的代码看起来不干净(检查例3)

此外,如果您决定从MySQL更改为SQLite,您不需要更改代码上的任何内容,但是要说Eloquent已经是ORM。

0

让我们打破你的好处之一清单按一个:

  1. 可测性(仓库可以被注入控制器)

这是真实的。后来在你的问题中,你说你可以轻松地将一个模型注入到控制器中,所以有什么意义?关键在于,如果使用接口来定义存储库方法,则可以在生产代码中使用具体存储库来实际查询雄辩模型,同时使用实现相同接口进行测试的“伪”存储库。我经常这样做,我的“假”实现只是使用一个Collection来保存我正在测试的模型。这样,您的测试运行得更快,您不必担心控制器测试中的迁移。它还使您不必在单元测试中与数据库进行交互。我并不是说它对数据库进行测试本质上是不好的,但是你应该在可能的情况下避免它。使用存储库可帮助您加速测试,而不需要需要与数据库进行交互。通过在您的控制器中键入存储库接口,您可以传入一个假实现进行测试,并将服务提供程序中的实际实现绑定到您的生产代码。

  • 抽象(复杂口才查询可以被重构到存储库功能)
  • 这是取决于你。 Laravel中存储库模式的问题在于,无论您尝试多么努力,模型都与数据库绑定。没有办法绕过它。您扩展应用程序并重新使用存储库的机会接近于零,因此这不一定是坏事。无论如何,业务逻辑不应该在您的模型存储库中,所以应用程序的核心(如果设计正确)仍然会从框架中抽象出来。在真实的存储库模式中,您的查询是在存储库中定义的。但是由于Laravel的模型与数据库紧密耦合,放置这​​个逻辑的位置并不重要。事实上,Laravel具有一些很好的雄辩功能,可能会使这种逻辑在您的模型中变得更直观。在Laravel中,存储库的真正亮点就是我在第一点提出的,能够在测试中从数据库中进行一些抽象。

  • 解耦(使我更换持久层)
  • 这是存储库模式的主点和正是使得点#1可能。当然,传递Eloquent模型意味着无论模型在哪里,数据库也是如此。这只是你必须与Active Record共存的事情。


    扩大对@ Lloope的回答,另一个好处是已经在一个地方定义了复杂的查询(无论是你的模型或仓库),以避免这样的代码在你的代码库乱丢:

    $professor->getStudents()->orderBy('name')->get(); 
    

    ,而使用这样的事情:

    $students = $usersRepository->getStudentsForProfessor($professor, 'name', 'ASC'); 
    

    与写作各地您的应用程序雄辩查询的问题是,随着需求的变化,你必须更新这些查询在您的应用程序中的任这可能只是在您的控制器中,或在您的应用程序的几十个不同部分。一个存储库上的方法(或者甚至只是你的Eloquent模型)更容易维护。这意味着您的其他物体不需要担心getStudentsForProfessor的功能或功能。他们只知道它会为给定的教授返回一批学生。存储库可以帮助您在一个地方组织查询逻辑。一旦你定义了这个界面,或者合同,你的其他对象可以依靠它来完成它所说的事情。随着查询需求的变化,您可以在一个地方更新实施,而不是在您的应用中全部更新。合同仍然是一样的。这比在任何地方编写雄辩的查询都有更大的灵活性。

    +0

    我试图用这个例子说的是,使用你的模型作为存储库层,你可以放下它们的方法并直接使用它,所以在这个例子中,它是德教授谁拥有方法'getStudents',然后你可以订购他们或分页或其他。如果您在存储库上执行相同的操作,则应该创建'getStudentsForProfessor','getStudentsForProfessorOrdered','getStudentsForProfessorPaginated','getStudentsForProfessorOrderedAndPaginated'等。 – Lloople

    +1

    我看到了。那么我会编辑我的答案。我为我的误会道歉 :) – samrap