站长资讯网
最全最丰富的资讯网站

浅析Laravel中存储库模式(Repository)的优点

为什么要在 Laravel 中使用存储库模式(Repository)?下面本篇文章给大家介绍一下使用存储库模式的优点,希望对大家有所帮助!

浅析Laravel中存储库模式(Repository)的优点

Laravel 9 保姆级视频教程,想学不会都难!进入学习

  • 1. Laravel中的存储库模式
  • 2. 为什么要在 Laravel 中使用存储库模式(Repository)?

在之前的文章中,我解释了什么是存储库模式,它与Active Record模式有何不同,以及如何在Laravel中实现它。现在我想深入了解一下为什么应该使用存储库模式。

我在上一篇文章的评论中注意到,Repository模式在Laravel社区中是一个有争议的话题。有些人认为没有理由使用它,并坚持使用内置的Active Record模式。其他人则倾向于使用其他方法将数据访问从逻辑域中分离出来。请注意,我尊重这些意见,并将在接下来的博客文章中专门讨论此主题。

有了这个免责声明,让我们来了解一下使用存储库模式的优点。

单一责任原则

单一责任原则是主要鉴别器来区分Active Record模式和存储库模式。模型类已经保存数据并提供域对象的方法。当使用Active Record模式时,数据访问是额外引入的责任。这是我想在以下示例中说明的东西:

/**  * @property string $first_name  * @property int    $company_id  */ class Employee extends Model {}  $jack = new Employee(); $jack->first_name = 'Jack'; $jack->company_id = $twitterId; $jack->save();
登录后复制

虽然域模型和数据访问技术的职责混合,但它直观上看还说得过去。在我们的应用程序中,员工必须以某种方式存储在数据库中,因此为什么不调用对象上的save()。单个对象被转化成单个数据行并存储。

但是,让我们更进一步,看看我们还能对员工做些什么:

$jack->where('first_name', 'John')->firstOrFail()->delete(); $competition = $jack->where('company_id', $facebookId)->get();
登录后复制

现在,它变得不直观,甚至违背了我们的域模型。 为什么 Jack 会突然删除另一个甚至可能在不同公司工作的员工? 或者他为什么能把 Facebook 的员工拉过来?

当然,这个例子是人为设计的,但它仍然显示了 Active Record 模式如何不允许有意的域模型。 员工与所有员工列表之间的界限变得模糊。 您始终必须考虑该员工是被用作实际员工还是作为访问其他员工的机制。

仓库模式通过强制执行这个基本分区来解决这个问题。它的唯一用途是标识域对象的合集,而不是域对象的本身。

要点:

  • 通过将所有域对象的集合与单个域对象分离, 仓库模式体现了单一责任原则

不要重复自己 (DRY)

一些项目将数据库查询洒遍了整个项目。下面是一个例子,我们从数据库中获取列表,并在 Blade 视图中显示他们。

class InvoiceController {      public function index(): View {         return view('invoices.index', [             'invoices' => Invoice::where('overdue_since', '>=', Carbon::now())                 ->orderBy('overdue_since')                 ->paginate()         ]);     } }
登录后复制

当这样的查询遍得更加复杂并且在多个地方使用时,考虑将其提取到 Repository 方法中。

存储库模式通过将重复查询打包到表达方法中来帮助减少重复查询。如果必须调整查询,只需更改一次即可。

class InvoiceController {      public __construct(private InvoiceRepository $repo) {}      public function index(): View {         return view('invoices.index', [             'invoices' => $repo->paginateOverdueInvoices()         ]);     } }
登录后复制

现在查询只实现一次,可以单独测试并在其他地方使用。此外,单一责任原则再次发挥作用,因为控制器不负责获取数据,而只负责处理HTTP请求和返回响应。

Takeaway:

  • ? 存储库模式有助于减少重复查询

依赖反转

解释 Dependency Inversion Principle 值得发表自己的博客文章。我只是想说明存储库可以启用依赖项反转。

在对组件进行分层时,通常较高级别的组件依赖于较低级别的组件。 例如,控制器将依赖模型类从数据库中获取数据:

class InvoiceController {     public function index(int $companyId): View {         return view(             'invoices.index',             ['invoices' => Invoice::where('company_id', $companyId)->get()]         );     } }
登录后复制

依赖关系是自上而下的,紧密耦合的。 InvoiceController 取决于具体的 Invoice 类。 很难将这两个类解耦,例如单独测试它们或替换存储机制。 通过引入 Repository 接口,我们可以实现依赖倒置:

interface InvoiceRepository {     public function findByCompanyId($companyId): Collection; }  class InvoiceController {     public function __construct(private InvoiceRepository $repo) {}      public function index(int $companyId): View {         return view(             'invoices.index',             ['invoices' => $this->repo->findByCompanyId($companyId)]         );     } }  class EloquentInvoiceRepository implements InvoiceRepository {     public function findByCompanyId($companyId): Collection {         // 使用 Eloquent 查询构造器实现该方法     } }
登录后复制

Controller 现在只依赖于 Repository 接口, 和 Repository 实现一样. 这两个类现在只依赖于一个抽象, 从而减少耦合. 正如我将在下一节中解释的那样,这会带来

赞(0)
分享到: 更多 (0)