原文鏈接:https://learnku.com/laravel/t/41757
討論請(qǐng)前往專(zhuān)業(yè)的 Laravel 開(kāi)發(fā)者論壇:https://learnku.com/Laravel
設(shè)計(jì)模式對(duì)每個(gè)開(kāi)發(fā)人員都很重要。它解決了您構(gòu)建的每個(gè)項(xiàng)目中非常常見(jiàn)的問(wèn)題伊履。
裝飾器模式定義:
它可以幫助您在一個(gè)對(duì)象上添加額外的行為漆际,而又不影響同一類(lèi)中的其他對(duì)象改淑。
維基百科:
裝飾器模式是一種設(shè)計(jì)模式香椎,它允許動(dòng)態(tài)地將行為添加到單個(gè)對(duì)象变擒,而不會(huì)影響同一類(lèi)中其他對(duì)象的行為
問(wèn)題
假設(shè)我們有一個(gè)Post模型
class Post extends Model
{
public function scopePublished($query) {
return $query->where('published_at', '<=', 'NOW()');
}
}
在我們的PostsController中颊艳,我們有如下的index方法
class PostsController extends Controller
{
public function index() {
$posts = Post::published()->get();
return $posts;
}
}
為了緩存帖子并避免每次我們需要列出帖子時(shí)都查詢(xún)數(shù)據(jù)庫(kù)投队,我們可以執(zhí)行以下操作
class PostsController extends Controller
{
public function index() {
$minutes = 1440; # 1 day
$posts = Cache::remember('posts', $minutes, function () {
return Post::published()->get();
});
return $posts;
}
}
現(xiàn)在枫疆,我們將帖子緩存1天。但看看代碼敷鸦,控制器了解了太多息楔。它知道我們緩存了多少天,它自己緩存了對(duì)象轧膘。
同樣钞螟,假設(shè)您正在為HomePageController的Tag,Category谎碍,Archives實(shí)現(xiàn)相同的功能鳞滨。閱讀和維護(hù)的代碼太多了。
倉(cāng)庫(kù)模式
在大多數(shù)情況下蟆淀,倉(cāng)庫(kù)模式是連接到裝飾器模式拯啦。
首先澡匪,讓我們使用倉(cāng)庫(kù)模式分離獲取帖子的方式,創(chuàng)建具有以下內(nèi)容的app/Repositories/Posts/PostsRepositoryInterface.php
namespace App\Repositories\Posts;
interface PostsRepositoryInterface
{
public function get();
public function find(int $id);
}
在同個(gè)目錄下創(chuàng)建具有下面內(nèi)容的 PostsRepository
namespace App\Repositories\Posts;
use App\Post;
class PostsRepository implements PostsRepositoryInterface
{
protected $model;
public function __construct(Post $model) {
$this->model = $model;
}
public function get() {
return $this->model->published()->get();
}
public function find(int $id) {
return $this->model->published()->find($id);
}
}
回到PostsController并將更改應(yīng)用為
namespace App\Http\Controllers;
use App\Repositories\Posts\PostsRepositoryInterface;
use Illuminate\Http\Request;
class PostsController extends Controller
{
public function index(PostsRepositoryInterface $postsRepo) {
return $postsRepo->get();
}
}
控制器變得健康褒链,知道足夠的細(xì)節(jié)來(lái)完成工作唁情。
在這里,我們依靠 Laravel 的 IOC 注入 Posts 接口的具體對(duì)象來(lái)獲取我們的帖子
我們需要做的就是告訴Laravel的IOC使用接口時(shí)要?jiǎng)?chuàng)建哪個(gè)類(lèi)甫匹。
在你的 app/Providers/AppServiceProvider.php
添加綁定方法
namespace App\Providers;
use App\Repositories\Posts\PostsRepositoryInterface;
use App\Repositories\Posts\PostsRepository;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostsRepositoryInterface::class,PostsRepository::class);
}
}
現(xiàn)在無(wú)論何時(shí)我們注入PostsRepositoryInterface
Laravel 都會(huì)創(chuàng)建 PostsRepository
的實(shí)例并將其返回甸鸟。
通過(guò)裝飾器實(shí)現(xiàn)緩存
我們?cè)谝婚_(kāi)始就說(shuō)過(guò),裝飾器模式允許將行為添加到單個(gè)對(duì)象兵迅,而不會(huì)影響同一類(lèi)中的其他對(duì)象抢韭。
在這里緩存是行為,對(duì)象/類(lèi)是 PostsRepository
恍箭。
讓我們?cè)?app/Repositories/Posts/PostsCacheRepository.php
中創(chuàng)建具有以下內(nèi)容的PostsCacheRepository
namespace App\Repositories\Posts;
use App\Post;
use Illuminate\Cache\CacheManager;
class PostsCacheRepository implements PostsRepositoryInterface
{
protected $repo;
protected $cache;
const TTL = 1440; # 1 day
public function __construct(CacheManager $cache, PostsRepository $repo) {
$this->repo = $repo;
$this->cache = $cache;
}
public function get() {
return $this->cache->remember('posts', self::TTL, function () {
return $this->repo->get();
});
}
public function find(int $id) {
return $this->cache->remember('posts.'.$id, self::TTL, function () {
return $this->repo->find($id);
});
}
}
在這個(gè)類(lèi)中刻恭,我們接受 Caching 對(duì)象和 PostsRepository 對(duì)象,然后使用類(lèi)(裝飾器)將緩存行為添加到 PostsReposiory 實(shí)例扯夭。
我們可以使用相同的示例將HTTP請(qǐng)求發(fā)送到某些服務(wù)鳍贾,然后在失敗的情況下返回模型。我相信您會(huì)從該模式以及它是如何輕松添加行為中受益交洗。
最后一件事是修改 AppServiceProvider 接口綁定以創(chuàng)建 PostsCacheRepository 實(shí)例而不是PostsRepository
namespace App\Providers;
use App\Repositories\Posts\PostsRepositoryInterface;
use App\Repositories\Posts\PostsCacheRepository;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostsRepositoryInterface::class,PostsCacheRepository::class);
}
}
現(xiàn)在再次檢查文件骑科,您會(huì)發(fā)現(xiàn)它非常易于閱讀和維護(hù)。同樣藕筋,它也是可測(cè)試的纵散,如果您決定在某個(gè)時(shí)候刪除緩存層。您只需在AppServiceProvider
中更改綁定即可隐圾。無(wú)需額外更改。
結(jié)論
- 我們學(xué)習(xí)了如何使用修飾器模式緩存模型
- 我們展示了倉(cāng)庫(kù)模式如何連接到修飾器模式
- 依附注入和Laravel IOC如何使我們的生活變得輕松
- laravel組件功能強(qiáng)大
希望您喜歡閱讀本文掰茶。它向您展示了強(qiáng)大的設(shè)計(jì)模式暇藏,以及如何使您的項(xiàng)目易于維護(hù)和管理
原文鏈接:https://learnku.com/laravel/t/41757
討論請(qǐng)前往專(zhuān)業(yè)的 Laravel 開(kāi)發(fā)者論壇:https://learnku.com/Larav