好記性不如爛筆頭,學習php開發也不能懶,作筆記是一種學習的好習慣!
文章來自:mp.weixin.qq.com/s/g_nJn271pjRJHTE...
學習與交流:Laravel技術交流微信群
Repository 模式主要思想是建立在一個資料操作代理層上的,把controller裡的資料操作分離出來,這樣做的好處有以下幾點:
1 把資料處理邏輯分離使得程式碼更容易維護
2 資料處理邏輯和業務邏輯分離,可以對這兩個程式碼分別進行測試
3 減少程式碼重複
4 降低程式碼出錯的機率
5 讓controller程式碼的可讀性大大提高
如圖所示Repository的分層關係
然而,要獨立一個操作層出來,那就會增加大量程式碼,非常繁瑣。如果你是小專案,未必需要使用這一模式。但如果是4-5年以上的複雜大型專案,這種模式的好處就比較明顯了。
學習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 App\Repositories\Interfaces;
Interface PostInterface{
public function findPosts(Array $cat_id,$is_draft,$order,$take)
{
}
}
第三步 建立一個介面對應的實現
在上面的Implements
目錄新建一個檔案PostRepository.php
:
namespace App\Repositories\Implements;
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();
return $query;
}
}
很明顯,倉庫指的就是一個倉庫介面的實現;這裡定義你的業務邏輯;
第四步 在ServiceProvider中繫結介面
開啟app/Providers/AppServiceProvider
, 在register()
加入程式碼:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
}
public function register()
{
$this->app->bind('App\Repositories\Interfaces\PostInterface', 'App\Repositories\Implements\PostRepository');
}
}
我們知道,ServiceProvider是Laravel IOC容器實現動態換介面實現的地方,所以我們在這裡繫結一下,這樣我們在使用的時候,不直接使用介面實現,而是用ioc容器解析介面,它會幫你自動找到對應好的實現。這就意味著,以後需要更換實現,可以在這裡更換;
第五步 使用倉庫
回到我們的controller裡來
use App\Repositories\Interfaces\PostInterface;
class PostController extends BaseController{
public function __construct(PostInterface $post){
$this->postRepo = $post;
}
public function index(){
$this->postRepo->findPosts([1,2],0,'desc',5);
}
}
從上面的例子看,我們的業務邏輯變得非常精簡,完全不用管查詢;而且也現實了資料查詢部分的解耦;
本作品採用《CC 協議》,轉載必須註明作者和本文連結