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

Laravel

原文連接: https://learnku.com/laravel/t...

討論請前往專業的 Laravel 開發者論壇: https://learnku.com/Laravel

設計模式對每一個開發人員都很重要。它解決了您構建的每一個項目中很是常見的問題。php

裝飾器模式定義:

它能夠幫助您在一個對象上添加額外的行爲,而又不影響同一類中的其餘對象。laravel

維基百科:

裝飾器模式是一種設計模式,它容許動態地將行爲添加到單個對象,而不會影響同一類中其餘對象的行爲

問題

假設咱們有一個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;
    }
}

爲了緩存帖子並避免每次咱們須要列出帖子時都查詢數據庫,咱們能夠執行如下操做緩存

class PostsController extends Controller
{
    public function index() {
        $minutes = 1440; # 1 day
        $posts = Cache::remember('posts', $minutes, function () {
            return Post::published()->get();
        });
        return $posts;
    }
}

如今,咱們將帖子緩存1天。但看看代碼,控制器瞭解了太多。它知道咱們緩存了多少天,它本身緩存了對象。app

一樣,假設您正在爲HomePageController的Tag,Category,Archives實現相同的功能。閱讀和維護的代碼太多了。ide

倉庫模式

在大多數狀況下,倉庫模式是鏈接到裝飾器模式。post

首先,讓咱們使用倉庫模式分離獲取帖子的方式,建立具備如下內容的app/Repositories/Posts/PostsRepositoryInterface.php學習

namespace App\Repositories\Posts;

interface PostsRepositoryInterface 
{

    public function get();

    public function find(int $id);

}

在同個目錄下建立具備下面內容的 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並將更改應用爲

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();
    }
}

控制器變得健康,知道足夠的細節來完成工做。

在這裏,咱們依靠 Laravel 的 IOC 注入 Posts 接口的具體對象來獲取咱們的帖子

咱們須要作的就是告訴Laravel的IOC使用接口時要建立哪一個類。

在你的 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);
    }
}

如今不管什麼時候咱們注入PostsRepositoryInterface Laravel 都會建立 PostsRepository 的實例並將其返回。

經過裝飾器實現緩存

咱們在一開始就說過,裝飾器模式容許將行爲添加到單個對象,而不會影響同一類中的其餘對象。

在這裏緩存是行爲,對象/類是 PostsRepository

讓咱們在 app/Repositories/Posts/PostsCacheRepository.php 中建立具備如下內容的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);
        });
    }
}

在這個類中,咱們接受 Caching 對象和 PostsRepository 對象,而後使用類(裝飾器)將緩存行爲添加到 PostsReposiory 實例。

咱們可使用相同的示例將HTTP請求發送到某些服務,而後在失敗的狀況下返回模型。我相信您會從該模式以及它是如何輕鬆添加行爲中受益。

最後一件事是修改 AppServiceProvider 接口綁定以建立 PostsCacheRepository 實例而不是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);
    }
}

如今再次檢查文件,您會發現它很是易於閱讀和維護。一樣,它也是可測試的,若是您決定在某個時候刪除緩存層。您只需在AppServiceProvider中更改綁定便可。無需額外更改。

結論

  • 咱們學習瞭如何使用修飾器模式緩存模型
  • 咱們展現了倉庫模式如何鏈接到修飾器模式
  • 依附註入和Laravel IOC如何使咱們的生活變得輕鬆
  • laravel組件功能強大

但願您喜歡閱讀本文。它向您展現了強大的設計模式,以及如何使您的項目易於維護和管理

原文連接: https://learnku.com/laravel/t...

討論請前往專業的 Laravel 開發者論壇: https://learnku.com/Larav
相關文章
相關標籤/搜索