如何组织代码以包装 API 缓存系统



我正在构建一个通过已经制作的库使用外部API的应用程序。让我们想象一下,这个外部服务提供给定地点的天气信息。我们有这样的控制器:

class WeatherController
{
public function show($place, WeatherLibrary $api)
{
return $api->getWeatherFor($place);
}
}

看起来没问题,但此 API 具有每分钟请求数限制,这需要缓存系统。我正在考虑使用Laravel提供的本机缓存API。但是,为了使我的代码井井有条,我想避免在我的控制器中使用逻辑的缓存部分,如下所示:

use IlluminateSupportFacadesCache;
class WeatherController
{
public function show($place, WeatherLibrary $api)
{
return Cache::get($place, function() use ($place, $api) {
$result = $api->getWeatherFor($place);
Cache::put($place, $result, 60);
return $result;
});
}
}

我应该采取什么方法来组织它?我在考虑存储库模式,但我不确定这是否是正确的方法,因为存储库至少具有类似 CRUD 的操作,并且这个"存储库"将根据外部服务业务逻辑具有自定义方法。

根据 bishop 的评论,您可以创建一个这样的代理类:

class WeatherLibraryProxy
{
/**
* @var WeatherLibrary
*/
protected $driver;
public function __construct(WeatherLibrary $driver)
{
$this->driver = $driver;
}

/**
* Catch all method calls and either serve results from the cache
* or defer to the underlying api driver and cache the result
*/
public function __call($method, $parameters)
{
$cache_key = $method . implode(',', $parameters);
return cache()->remember(
$cache_key,
now()->addMinutes(60),
function () use ($method, $parameters) {
return $this->driver->$method(...$parameters);
});
}
}

现在,任何共享功能(如检查剩余速率限制)都可以放入您的代理类中,您可以在应用中的任何位置使用该类,而不是基础 WeatherLibrary 类。

然后在控制器中,将WeatherLibrary更改为WeatherLibraryProxy

class WeatherController
{
public function show($place, WeatherLibraryProxy $api)
{
return $api->getWeatherFor($place);
}
}

Laravel 的服务容器应该自动将 WeatherLibrary 注入到代理的构造函数中。如果没有,那么您可以指示Laravel如何在AppServiceProvider中构建新实例.php:

$this->app->bind(WeatherLibrary::class, function ($app) {
return new WeatherLibrary($arg1, $arg2, ...);
});

有关自动注射的更多信息:https://laravel.com/docs/6.0/container#automatic-injection

最新更新