假设我有一个PostController控制器和一个post模型。下面是我如何编写代码的场景。
1.我可以在控制器中有一个构造函数,并在那里注入Post模型。就像这样:
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);
}
1.我可以直接在函数中编写Post模型(show函数)。
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function show($id){
return Post::find($id);
}
1.我可以有一个存储库类,它扩展了我的Eloquent 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);
}
}
1.我可以有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提供了一种模拟Eloquent模型的方法。为什么这种方法不好?我知道这很糟糕,我只是不知道为什么,因为我仍然可以嘲笑雄辩和测试它。
问题2:第二个例子和第一个例子有什么区别?如果我可以测试它并模拟一个Eloquent模型,如果它在一个函数中被直接访问,为什么要在构造函数中注入它呢?
问题3)假设我不使用存储库模式。创建存储库类并不意味着使用存储库模式。仓库模式是当使用接口时,您可以交换(例如从Eloquent到其他ORM)。假设我总是知道我将只使用Eloquent,并且我不想将我的代码与框架本身解耦。那么问题是为什么要使用第三和第四个例子中所示的存储库类呢?我问这个问题是因为人们说最好把复杂的逻辑放在存储库中,而不是放在模型中。
问题4:第三个例子和第四个例子有什么区别?我还可以测试第四个例子。为什么要在构造函数中注入PostRepository?
1条答案
按热度按时间des4xlb01#
问题1:假设我使用第二个例子。我直接访问Post模型。它是可测试的,因为laravel提供了一种模拟雄辩模型的方法。为什么这种方法不好?我知道这不好,我只是不知道为什么,因为我仍然可以模仿口才和测试它。
只有当你有一个需要交换存储层的大型应用程序时,这才是糟糕的。如果你永远不会把存储层从DB改为其他的东西,这是一个不错的方法,而且它完全是可测试的。
问题2:第二个例子和第一个例子有什么区别?如果我可以测试它并模拟一个有说服力的模型,如果它可以在函数中直接访问,为什么要将它注入到构造函数中呢?
第二个例子和第一个例子之间没有区别。这是因为存储库实现不正确。它不应该扩展Post类。它实际上应该实现一个带有select方法的接口,如下所示:
然后,在您的服务提供商中,将合约绑定到数据库存储库,如下所示:
这样,如果您想换出实现,只需如上所述更改绑定即可。
问题3)假设我不使用存储库模式。创建存储库类并不意味着使用存储库模式。存储库模式是当使用接口时,您可以交换(例如从雄辩到其他ORM)。假设我总是知道我将只使用雄辩的,我不想从框架本身解耦我的代码。那么问题是为什么要使用第三和第四个例子中所示的存储库类呢?我问这个问题是因为人们说最好把复杂的逻辑放在存储库中,而不是放在模型中。
如果您知道您将只使用Eloquent,那么就不应该使用Repository模式。
问题4:第三个例子和第四个例子有什么区别?我还可以测试第四个例子。为什么要在构造函数中注入PostRepository?
您的示例的实现不正确。不应该在构造函数中添加具体类以进行依赖注入。相反,您应该像这样添加接口:
这样,您就可以交换实现,而无需更改上面的代码。
此外,正如@Polaris在评论中提到的,您不应该将数据作为集合或雄辩的模型返回。否则,它将破坏使用Repository模式的全部目的。返回一个数组或者一个单独的Post类(非Eloquent类,也不特定于某个实现)。