Php 我应该在控制器的构造函数中注入存储库类还是模型类?
我希望你能读到这篇文章,并以非常明智的方式向我解释。我真的非常感激。我知道很多,但还是谢谢你 假设我有一个PostController控制器和一个post模型。以下是我如何编写代码的场景 我可以在控制器中有一个构造函数,并在那里注入Post模型。像这样:Php 我应该在控制器的构造函数中注入存储库类还是模型类?,php,laravel,Php,Laravel,我希望你能读到这篇文章,并以非常明智的方式向我解释。我真的非常感激。我知道很多,但还是谢谢你 假设我有一个PostController控制器和一个post模型。以下是我如何编写代码的场景 我可以在控制器中有一个构造函数,并在那里注入Post模型。像这样: class PostController extends Controller { /** * Display a listing of the resource. * * @return \Illumin
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
$post;
public function __construct(Post $post){
$this->post = $post;
}
public function show($id){
return $this->post->find($id);
}
2我可以直接在函数show函数中编写Post模型
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function show($id){
return Post::find($id);
}
3我可以拥有一个repository类,它扩展了我雄辩的Post模型,并将其注入构造函数
class PostRepository extends Post{
}
class PostController extends Controller{
protected $post;
public function __construct(PostRepository $post){
$this->postRepo = $post;
}
public function show($id){
return $this->postRepo->find($id);
}
}
4我可以拥有postRepository,而无需注入和直接使用它
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function show($id){
return PostRepository::find($id);
}
我希望你能理解所有这些例子。让我们谈谈我的问题以及我是如何看待它的。在我开始讲话之前,我想让你们知道,我希望我的代码是可测试的,并且写得很好
问题1假设我使用第二个例子。我直接访问那里的Post模型。它是可测试的,因为laravel提供了一种模拟雄辩模型的方法。为什么这是一个糟糕的方法?我知道这很糟糕,我只是不知道为什么,因为我仍然可以嘲笑雄辩,并测试它
问题2第二个例子和第一个例子有什么区别?如果我可以测试它并模拟一个雄辩的模型(如果它直接在函数中访问),那么为什么要将它注入构造函数呢
问题3假设我不使用存储库模式。创建存储库类并不意味着使用存储库模式。存储库模式是在使用接口时使用的,例如,您可以从Elount交换到其他ORM。假设我一直都知道我只会使用雄辩的,我不想将我的代码与框架本身分离。然后问题是为什么要使用存储库类,如第三个和第四个示例所示?我这样问是因为人们说最好将复杂的逻辑放在存储库中,而不是放在模型中
问题4第三个和第四个例子有什么区别?我仍然可以测试第四个示例。为什么要在构造函数中注入PostRepository
问题1假设我使用第二个例子。我正在直接访问
在那里张贴模型。它是可测试的,因为laravel提供了一种模拟的方法
雄辩的模型。为什么这是一个糟糕的方法?我知道这很糟糕,我只是
不知道为什么,因为我仍然可以模仿雄辩,并测试它
只有当你有一个需要更换存储层的大型应用时,这才是糟糕的。如果您永远不会将存储层从DB更改为其他内容,那么这绝对不是一个坏方法,而且完全可以测试
问题2第二个和第一个有什么区别
实例如果我能测试它,并模仿一个雄辩的模型,如果它是直接
在函数中访问,为什么要将其注入构造函数
第二个和第一个示例之间没有区别。这是因为存储库实现不正确。它不应该扩展Post类。事实上,它应该实现一个带有select方法的接口,如下所示:
class PostDatabaseRepository extends PostRepositoryContract {
public function show($id){
return Post::find($id)->toArray();
}
...
}
然后,在服务提供商中,将合同绑定到数据库存储库,如下所示:
$this->app->singleton(
PostRepositoryContract::class, PostDatabaseRepository::class
);
这样,如果您想交换实现,只需如上所述更改绑定即可
问题3假设我不使用存储库模式。创建
存储库类并不意味着使用存储库模式。存储库
模式是指当使用接口时,您可以交换接口,例如从
对其他ORM有口才。假设我一直知道我只会使用
而且我不想将我的代码与框架本身分离。
然后问题是为什么要使用存储库类,如中所示
第三和第四个例子?我问这个是因为人们都这么说
最好将复杂的逻辑放在存储库中,而不是放在模型中
如果您知道您将只使用雄辩,那么不应该使用存储库模式
问题4第三个和第四个有什么区别
实例我仍然可以测试第四个示例。为什么要注射
构造函数中的PostRepository
您的示例的实现不正确。不应在构造函数中添加具体类以进行依赖项注入。相反,您应该像这样添加接口:
public function __construct(PostRepositoryContract $post){
$this->postRepo = $post;
}
通过这种方式,您可以交换实现,而无需更改上述代码
此外,正如@Polaris在评论中提到的,您不应将数据作为集合或雄辩的模型返回。否则,它将破坏使用存储库模式的全部目的。返回一个数组,或者可能是一个单独的Post类,该类没有说服力,也不特定于某个实现。说得好,向上投票。我只想补充一点,如果您决定使用存储库模式,那么应该将数据作为数组而不是集合或雄辩的模型返回。否则它将破坏使用存储库模式的全部目的。我同意@Polaris已将实现更改为返回数组。谢谢非常感谢。我想你的第二个
答案是错的,因为我的第二个问题是另外一个问题。我还看到人们在构造函数中注入存储库而不是接口。因为他们不想让存储库模式交换实现,但他们想让函数和复杂的函数在存储库中,而不是直接在模型中。@NikaKhurashvili在构造函数中注入特定的实现违背了存储库模式的目的,是一种不好的做法。这样做的人只是做错了。在任何好的框架或包中,您都不会看到这一点。我并不是说在构造函数中传递存储库类是一种存储库模式。我知道什么是存储库模式。我刚刚看到一些例子,人们将特定的存储库类传递给构造函数,因为他们不想在控制器或模型中编写大型逻辑。你明白吗?