如何在 Laravel 中使用 PHP 的裝飾器模式

Laravel

原文鏈接: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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市濒蒋,隨后出現(xiàn)的幾起案子盐碱,更是在濱河造成了極大的恐慌,老刑警劉巖沪伙,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓮顽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡围橡,警方通過(guò)查閱死者的電腦和手機(jī)暖混,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)翁授,“玉大人拣播,你說(shuō)我怎么就攤上這事晾咪。” “怎么了贮配?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵谍倦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我泪勒,道長(zhǎng)昼蛀,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任圆存,我火速辦了婚禮叼旋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辽剧。我一直安慰自己送淆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布怕轿。 她就那樣靜靜地躺著偷崩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撞羽。 梳的紋絲不亂的頭發(fā)上阐斜,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音诀紊,去河邊找鬼谒出。 笑死,一個(gè)胖子當(dāng)著我的面吹牛邻奠,可吹牛的內(nèi)容都是我干的笤喳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碌宴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼杀狡!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起贰镣,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤呜象,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后碑隆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體恭陡,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年上煤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了休玩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖哥捕,靈堂內(nèi)的尸體忽然破棺而出牧抽,到底是詐尸還是另有隱情,我是刑警寧澤遥赚,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布扬舒,位于F島的核電站,受9級(jí)特大地震影響凫佛,放射性物質(zhì)發(fā)生泄漏讲坎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一愧薛、第九天 我趴在偏房一處隱蔽的房頂上張望晨炕。 院中可真熱鬧,春花似錦毫炉、人聲如沸瓮栗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)费奸。三九已至,卻和暖如春进陡,著一層夾襖步出監(jiān)牢的瞬間愿阐,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工趾疚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缨历,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓糙麦,卻偏偏與公主長(zhǎng)得像辛孵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赡磅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容