如何组织代码以环绕 API 缓存系统
How to organize code to wrap around an API a cache system
我正在构建一个应用程序,它通过一个已经创建的库使用外部 API。让我们想象一下这个外部服务提供给定地点的天气信息。我们有这样的控制器:
class WeatherController
{
public function show($place, WeatherLibrary $api)
{
return $api->getWeatherFor($place);
}
}
看起来不错,但是这个 API 有每分钟的请求数限制,因此需要缓存系统。我正在考虑使用 API Laravel 提供的本机缓存。但是,为了保持我的代码井井有条,我想避免在我的控制器中使用逻辑的缓存部分,如下所示:
use Illuminate\Support\Facades\Cache;
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 的操作,并且此“存储库”将根据外部服务具有自定义方法业务逻辑。
根据主教的评论,您可以像这样创建一个代理 class:
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);
});
}
}
现在任何共享功能(如检查剩余速率限制)都可以放入您的代理 class,您可以在您的应用程序的任何地方使用它,而不是底层的 WeatherLibrary class。
然后在您的控制器中,将 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
我正在构建一个应用程序,它通过一个已经创建的库使用外部 API。让我们想象一下这个外部服务提供给定地点的天气信息。我们有这样的控制器:
class WeatherController
{
public function show($place, WeatherLibrary $api)
{
return $api->getWeatherFor($place);
}
}
看起来不错,但是这个 API 有每分钟的请求数限制,因此需要缓存系统。我正在考虑使用 API Laravel 提供的本机缓存。但是,为了保持我的代码井井有条,我想避免在我的控制器中使用逻辑的缓存部分,如下所示:
use Illuminate\Support\Facades\Cache;
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 的操作,并且此“存储库”将根据外部服务具有自定义方法业务逻辑。
根据主教的评论,您可以像这样创建一个代理 class:
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);
});
}
}
现在任何共享功能(如检查剩余速率限制)都可以放入您的代理 class,您可以在您的应用程序的任何地方使用它,而不是底层的 WeatherLibrary class。
然后在您的控制器中,将 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