摘要:確實,要獨立一個操作層出來,確實會增加大量代碼,非常繁瑣。如果你是小項目,未必需要使用這一模式。但如果是年以上的復雜大型項目,這種模式的好處就比較明顯了。如果你是純新手,建議你暫時不要往下看,先把用得比較熟練后再回來學習。
為什么要學習Repository Pattern(倉庫模式)
Repository 模式主要思想是建立一個數據操作代理層,把controller里的數據操作剝離出來,這樣做有幾個好處:
把數據處理邏輯分離使得代碼更容易維護
數據處理邏輯和業務邏輯分離,可以對這兩個代碼分別進行測試
減少代碼重復
降低代碼出錯的幾率
讓controller代碼的可讀性大大提高
然而,據很多同學反應,這一部分很難學。確實,要獨立一個操作層出來,確實會增加大量代碼,非常繁瑣。如果你是小項目,未必需要使用這一模式。但如果是4-5年以上的復雜大型項目,這種模式的好處就比較明顯了。
如果你是純新手,建議你暫時不要往下看,先把laravel用得比較熟練后再回來學習。
學習Repository Pattern的意義不只是為了使用它,更會讓你深入思考框架的分層思想,你開始不僅關注怎么使用一個框架,還會想了解怎樣設計一個框架,也許會成為你往高階段編程的入口。
什么是Repository Pattern雖然說設計模式和語言及框架無關,但是脫離了語言及框架,我們很難理解,所以我們還是在laravel的語境下來學習吧:
public function index() { $posts = Post::whereIn("category_id",[1,2])->where("is_draft",0)->orderBy("created_at", "desc")->take(5)->get(); return view("front.index",compact("posts")); }
以上是典型的Eloquent數據查詢代碼,如果你編程經驗豐富,你會發現這種代碼在控制器里到處都是,而且有很多是重復的,可讀性很差;我們的目標是把它精簡:
仔細觀察
Post::whereIn("category_id",[1,2])->where("is_draft",0)->orderBy("created_at", "desc")->take(5)->get();
其實它由3部分組成,第一是Post,數據模型;第二個是whereIn("category_id",[1,2])->where("is_draft",0)->orderBy("created_at", "desc")->take(5),數據操作條件;第三個是get(),數據獲取的方法;
我們知道,Eloquent里有個Query Scope,可以用來把第二部分,也就是查詢條件精簡。所以,在使用了Query Scope后,我們可以把精簡成:
Post::ofCategory([1,2])->isDraft()->orderBy("created_at", "desc")->take(5)->get();
咋一看上去,好像也沒怎么精簡啊,但實際上你已經實現代碼解耦和復用了,比如說isDraft(), 這個代碼可以到處用,而不用擔心耦合問題。
精簡程度和你的邏輯抽象程度有關,比如說你完全可以寫成:
Post::findPosts([1,2],0,"desc",5)->get();
在輕型項目中,強烈推薦使用Query Scope,這是一種良好的編程習慣。
在更復雜的項目中,Query Scope就不夠用了,因為它和數據模型還是一種強耦合,Repository Pattern就是要把第一,第二,第三部分全部解耦;
說到解耦,我們在Laravel的文檔攻略中講過,第一神器就是PHP中的接口(Interface),下面來看例子:
第一步——建立文件夾
app
Repositories
Interfaces
Implements
Interfaces里面用來放接口,Implements用來放接口的實現;
第二步——建立一個接口
在上面的Interfaces目錄新建一個文件PostInterface.php:
namespace AppRepositoriesInterfaces; Interface PostInterface{ public function findPosts(Array $cat_id,$is_draft,$order,$take){ } }
第三步——建立一個接口對應的實現
在上面的Implements目錄新建一個文件PostRepository.php:
namespace AppRepositoriesImplements; use Post; class PostRepository Implements PostInterface{ public function findPosts(Array $cat_id,$is_draft,$order,$take){ $query = Post::whereIn("category_id",$cat_id)->where("is_draft",$is_draft)->orderBy("created_at", $order)->take($take)->get(); } }
看這里,很明顯,倉庫指的就是一個倉庫接口的實現;這里定義你的業務邏輯;
第四步——在ServiceProvider中綁定接口
打開app/Providers/AppServiceProvider, 在register() 加入代碼:
app->bind("AppRepositoriesInterfacesPostInterface", "AppRepositoriesImplementsPostRepository"); } }
我們知道,ServiceProvider是Laravel IOC容器實現動態換接口實現的地方,所以我們在這里綁定一下,這樣我們在使用的時候,不直接使用接口實現,而是用ioc容器解析接口,它會幫你自動找到對應好的實現。
這就意味著,以后需要更換實現,可以在這里更換;
第四步——使用倉庫
回到我們的controller里來:
use AppRepositoriesInterfacesPostInterface; class PostController extends BaseController{ public function __construct(PostInterface $post){ $this->postRepo = $post; } public function index(){ $this->postRepo->findPosts([1,2],0,"desc",5); } }
這樣你看,第一,我們的業務邏輯變得非常精簡,完全不用管查詢;第二,現實了數據查詢部分的解耦;
到這里,有同學就會問了,一開始說好的三個部分解耦呢,你這里只實現了第二部分啊;
確實,為了最快讓大家明白什么是Repository,我把第一和第二部分的解耦省略了,我們放到這篇文章的系列后續講。
你或許還有不少疑惑,我費那么大勁,寫成最后這個樣子,好像也沒什么區別啊。聰明的同學可能想到一點,如果采用Repository Pattern的話,是不是意味著以后我可以先在controller里寫成$this->postRepo->findPosts([1,2],0,"desc",5); 具體的查詢邏輯先不寫,然后我快速先把 整個應用的業務邏輯先跑一遍,然后再回頭一個一個寫接口實現來支持業務邏輯;(哇擦,太NB了,媽媽再也不用擔心SB客戶/PM改變需求了);
恭喜,你已經進入高級編程里說的DDD(Domain Driven Design 領域驅動設計)大門了,事實上,整個Laravel框架的核心架構就是這樣干的,IOC+接口,我們會在后續系列文章里介紹;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21511.html
摘要:按照最初提出者的介紹,是銜接數據映射層和領域層之間的一個紐帶,作用相當于一個在內存中的域對象集合。客戶端對象把查詢的一些實體進行組合,并把它們提交給。同時支持登錄過期時間設置,登錄之前,登錄之后事件處理。 laravel 開發輔助工具 配置 添加服務提供商 將下面這行添加至 config/app.php 文件 providers 數組中: providers => [ ... ...
摘要:但在中也不可避免的基礎模式,上述問題仍然存在。這樣可以完全分離和的依賴。最開始在中使用是通過定義大量的來注入,,實現具體的工作類。但是像鏈接調用仍然沒有解決,為些我們開發出了新的倉庫包。目前此包已經使用在好幾個項目中目前運行良好。 什么是Repository模式,如何使用Repository模式 這里就不再啰嗦了,請參見以下幾個鏈接如何使用 Repository 模式?關于 Repos...
摘要:原文來自模式為了保持代碼的整潔性和可讀性,使用是非常有用的。這是一個很典型的一段代碼使用和數據庫交互,這段代碼工作的很正常,但是層對于而言將是緊耦合的。 原文來自http://vegibit.com/laravel-repository-pattern/ Repository 模式 為了保持代碼的整潔性和可讀性,使用Repository Pattern 是非常有用的。事實上,我們也不必...
摘要:業務層,業務層,是最為核心的一層。對于和的狀態保存恢復也通過處理。對于的綁定操作和命令操作都是暴露的,也易于測試。需要注意的是標簽的節點中要使用到根節點中標簽里設置的的話需要這樣設置抽象類中設置了和注解,只起到清晰提醒作用。 原文發表于:Rockos blog(rocko.xyz)] - MVVM_Android-CleanArchitecture 前言 Architecture is...
閱讀 2164·2023-04-26 00:43
閱讀 2685·2021-11-22 15:22
閱讀 3816·2021-11-11 16:55
閱讀 969·2021-11-04 16:06
閱讀 1787·2019-08-30 14:12
閱讀 999·2019-08-30 14:02
閱讀 3368·2019-08-29 17:05
閱讀 1417·2019-08-29 12:27