PHP 中的设计模式:装饰器(使用 Laravel)装饰器模式定义:维基百科:问题存储库模式通过装饰器实现缓存结论

2025-06-08

PHP 中的设计模式:装饰器(使用 Laravel)

装饰器模式定义:

维基百科:

问题

存储库模式

通过Decorator实现缓存

结论

设计模式对于每个开发人员都非常重要。它解决了您构建的每个项目中非常常见的问题。

装饰器模式定义:

它可以帮助您在对象上添加额外的行为,而不会影响同一类的其他对象,看看这意味着什么。

维基百科:

装饰器模式是一种设计模式,允许动态地将行为添加到单个对象,而不会影响同一类中其他对象的行为

问题

假设我们有一个 Post 模型

class Post extends Model
{
    public function scopePublished($query) {
        return $query->where('published_at', '<=', 'NOW()');
    }
}

在我们的 PostsController 中,我们有如下所示的索引方法

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 天。但是查看代码。控制器知道的太多了。它知道我们缓存了多少天,它自己启动缓存对象。

另外,想象一下您正在为 HomePageController 的标签、类别、档案实现相同的功能。阅读和维护起来会非常困难。

存储库模式

在大多数情况下,存储库模式与装饰器模式是相连的,您将看到它们是如何相连的。

首先,让我们分开如何使用存储库模式获取帖子,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);
    }
}

现在,无论何时我们注入,PostsRepositoryInterfacelaravel 都会创建一个实例PostsRepository并将其返回。

通过Decorator实现缓存

我们在开始时就说过,装饰器模式允许将行为添加到单个对象,而不会影响同一类的其他对象。

这里的缓存是行为,对象/类是 PostsRepository

让我们PostsCacheRepository在同一个路径下创建app/Repositories/Posts/PostsCacheRepository.php以下内容


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 对象,然后我们使用该类(Decorator)向 PostsRepository 实例添加缓存行为。

我们可以使用相同的示例向某个服务发送 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。不需要进行任何额外的更改。

结论

  • 我们学习了如何使用装饰器模式缓存模型
  • 我们展示了存储库模式如何与装饰器模式连接
  • DependecyInjection 和 Laravel IOC 如何让我们的生活变得轻松
  • Laravel 组件有多强大

希望您喜欢阅读这篇文章。它向您展示了设计模式的强大功能以及它如何使您的项目易于维护和管理。

鏂囩珷鏉ユ簮锛�https://dev.to/ahmedash95/design-patterns-in-php-decorator-with-laravel-5hk6
PREV
使用 Rest API、Spring Boot、Maven 和 Fauna 构建任务管理应用程序
NEXT
收益率回报解释!