淺析Laravel中儲存庫模式(Repository)的優點
為什麼要在 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 查询构造器实现该方法 } }
這兩個類現在只依賴於一個抽象, 從而減少耦合. 正如我將在下一節中解釋的那樣,這會帶來更多優勢.
Takeaway:
- ? 存储库模式作为一种抽象类,支持依赖反转.
抽象类
存储库 提高了可读性 因为复杂的操作被具有表达性名称的高级方法隐藏了.
访问存储库的代码与底层数据访问技术分离. 如有必要,您可以切换实现,甚至可以省略实现,仅提供 Repository 接口。 这对于旨在与框架无关的库来说非常方便。
OAuth2 服务包 —— league/oauth2-server
也用到这个抽象类机制。 Laravel Passport 也通过 实现这个库的接口 集成 league/oauth2-server 包。
正如 @bdelespierre 在 评论 里回应我之前的一篇博客文章时向我指出的那样,你不仅可以切换存储库实现,还可以将它们组合在一起。大致以他的示例为基础,您可以看到一个存储库如何包装另一个存储库以提供附加功能:
interface InvoiceRepository { public function findById(int $id): Invoice; } class InvoiceCacheRepository implements InvoiceRepository { public function __construct( private InvoiceRepository $repo, private int $ttlSeconds ) {} public function findById(int $id): Invoice { return Cache::remember( "invoice.$id", $this->ttlSeconds, fn(): Invoice => $this->repo->findById($id) ); } } class EloquentInvoiceRepository implements InvoiceRepository { public function findById(int $id): Invoice { /* 从数据库中取出 $id */ } } // --- 用法: $repo = new InvoiceCacheRepository( new EloquentInvoiceRepository(); );
要点:
- ? 存储库模式抽象了有关数据访问的详细信息。
- ? 存储库将客户端与数据访问技术分离。
- ? 这允许切换实现,提高可读性并实现可组合性。
可测试性
存储库模式提供的抽象也有助于测试。
如果你有一个 Repository 接口,你可以提供一个替代的测试实现。 您可以使用数组支持存储库,而不是访问数据库,将所有对象保存在数组中:
class InMemoryInvoiceRepository implements InvoiceRepositoryInterface { private array $invoices; // implement the methods by accessing $this->invoices... } // --- Test Case: $repo = new InMemoryInvoiceRepository(); $service = new InvoiceService($repo);
通过这种方法,您将获得一个现实的实现,它速度很快并且在内存中运行。 但是您必须为测试提供正确的 Repository 实现,这 ** 本身可能需要大量工作**。 在我看来,这在两种情况下是合理的:
您正在开发一个(与框架无关的)库,它本身不提供存储库实现。
测试用例复杂,Repository 的状态很重要。
另一种方法是“模仿”,要使用这种技术,你不需要适当的接口。你可以模仿任何 non-final 类。
使用 PHPUnit API ,您可以明确规定如何调用存储库以及应该返回什么。
$companyId = 42; /** @var InvoiceRepository&MockObject */ $repo = $this->createMock(InvoiceRepository::class); $repo->expects($this->once()) ->method('findInvoicedToCompany') ->with($companyId) ->willReturn(collect([ /* invoices to return in the test case */ ])); $service = new InvoiceService($repo); $result = $service->calculateAvgInvoiceAmount($companyId); $this->assertEquals(1337.42, $result);
有了 mock,测试用例就是一个适当的单元测试。上面示例中测试的唯一代码是服务。没有数据库访问,这使得测试用例的设置和运行非常快速。
另外:
- ? 仓库模式允许进行适当的单元测试,这些单元测试运行快并且是隔离的。
原文地址:https://dev.to/davidrjenni/why-use-the-repository-pattern-in-laravel-2j1m
译文地址:https://learnku.com/laravel/t/62521
【相关推荐:laravel视频教程】
以上是淺析Laravel中儲存庫模式(Repository)的優點的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

PHP仍然流行的原因是其易用性、靈活性和強大的生態系統。 1)易用性和簡單語法使其成為初學者的首選。 2)與web開發緊密結合,處理HTTP請求和數據庫交互出色。 3)龐大的生態系統提供了豐富的工具和庫。 4)活躍的社區和開源性質使其適應新需求和技術趨勢。

IIS和PHP可以兼容,通過FastCGI實現。 1.IIS通過配置文件將.php文件請求轉發給FastCGI模塊。 2.FastCGI模塊啟動PHP進程處理請求,提高性能和穩定性。 3.實際應用中需注意配置細節、錯誤調試和性能優化。

Laravel適合團隊熟悉PHP且需功能豐富的項目,Python框架則視項目需求而定。 1.Laravel提供優雅語法和豐富功能,適合需要快速開發和靈活性的項目。 2.Django適合複雜應用,因其“電池包含”理念。 3.Flask適用於快速原型和小型項目,提供極大靈活性。

多次調用session_start()會導致警告信息和可能的數據覆蓋。 1)PHP會發出警告,提示session已啟動。 2)可能導致session數據意外覆蓋。 3)使用session_status()檢查session狀態,避免重複調用。

Laravel優化Web開發流程的方法包括:1.使用路由系統管理URL結構;2.利用Blade模板引擎簡化視圖開發;3.通過隊列處理耗時任務;4.使用EloquentORM簡化數據庫操作;5.遵循最佳實踐提高代碼質量和可維護性。

AI可以幫助優化Composer的使用,具體方法包括:1.依賴管理優化:AI分析依賴關係,建議最佳版本組合,減少衝突。 2.自動化代碼生成:AI生成符合最佳實踐的composer.json文件。 3.代碼質量提升:AI檢測潛在問題,提供優化建議,提高代碼質量。這些方法通過機器學習和自然語言處理技術實現,幫助開發者提高效率和代碼質量。

最新版本的Laravel10與MySQL5.7及以上、PostgreSQL9.6及以上、SQLite3.8.8及以上、SQLServer2017及以上兼容。這些版本選擇是因為它們支持Laravel的ORM功能,如MySQL5.7的JSON數據類型,提升了查詢和存儲效率。

Laravel和Yii的主要區別在於設計理念、功能特性和使用場景。 1.Laravel注重開發的簡潔和愉悅,提供豐富的功能如EloquentORM和Artisan工具,適合快速開發和初學者。 2.Yii強調性能和效率,適用於高負載應用,提供高效的ActiveRecord和緩存系統,但學習曲線較陡。
