如何重构自定义 http 客户端 class?
How to refactor custom http client class?
我的项目中有一个用于 http 客户端 class 的 class 我需要添加日志和持续时间。
这是class:
class RestClient {
public static function get($provider, $step, $url, $headers = [], $data = [])
{
return self::request(
Http::acceptJson()->withHeaders($headers),
'get',
$url,
$provider,
$step,
$data
);
}
private static function request($pendingRequest, $method, $url, $provider, $step, $data = [])
{
$startTime = microtime(true);
$client = $pendingRequest->{$method}($url, $data);
$durationTime = microtime(true) - $startTime;
if ($client->clientError() || $client->serverError()) {
HttpLog::addErrorLog(
$provider, $step, $data, $client->toException()->getMessage(), $url, $durationTime
);
if ($client->status() == 401) {
throw new InvalidTokenException();
}
if ($client->serverError()) {
throw new ServerException();
}
throw new ProviderException('ProviderException');
}
HttpLog::addLog(
$provider, $step, $client, $url, $durationTime
);
return $client->json();
}
}
我在项目的多个位置调用了 RestClient get 方法和其他方法。
调用示例:
return RestClient::get(
$this->providerName(),
'INQUIRY',
{$this->configs['base_url'],
['Authorization' => "Bearer $token",]
);
是否需要重构 RestClient class?
我建议减少参数的数量。
考虑使用链接而不是静态方法。
示例:
$restClient = new RestClient;
$restClient->provider($this->providerName());
$restClient->step("INQUIRY");
$restClient->url($this->configs['base_url']);
$restClient->headers(['Authorization' => "Bearer $token",]);
$restClient->get();
我认为链接使用起来会更方便
不知道你所说的“重构”到底是什么意思。
但如果你问的是扩展现有服务行为的最佳方式,我会说它是模式装饰器。但它需要摆脱静态方法。
此外,最好将 RestClient 注册为 DI 容器中的服务(如果您使用的是 Lumen,这里是手册 https://lumen.laravel.com/docs/5.6/container)
结果代码可能如下所示:
interface RestClientInterface
{
public function get(string $url, array $data): array;
public function post(string $url, array $data): array;
}
class RestClient implements RestClientInterface
{
private $provider;
public function __construct(ProviderInterface $provider) {
$this->provider = $provider;
}
public function get(string $url, array $data): array {
// do actual GET request using provider and return response, no additional actions
}
public function post(string $url, array $data): array {
// do actual POST request using provider and return response, no additional actions
}
}
class LoggingClient implements RestClientInterface
{
private $decorated;
public function __construct(RestClientInterface $decorated) {
$this->decorated = $decorated;
}
public function get(string $url, array $data): array {
$result = $this->decorated->get($url, $data);
// here do additional actions, logging etc
return $result;
}
public function post(string $url, array $data): array {
$result = $this->decorated->get($url, $data);
// here do additional actions, logging etc
return $result;
}
}
然后在容器中注册客户端实现并使用所需的装饰器对其进行扩展:
$this->app->bind(RestClient::class, function ($app) {
return new RestClient(new MyProvider());
});
$this->app->extend(RestClient::class, function ($decoratedClient, $app) {
return new LoggingClient($decoratedClient);
});
然后在代码中获取客户端实例:
$client = $this->app->make(RestClient::class); // or App::make(RestClient::class)
通过这种方法,您可以将服务包装在多个装饰器中,每个装饰器将负责执行一项附加操作。它提供了更大的灵活性。
$service = new DecoratorOne(new DecoratorTwo(new BasicImplementation()));
我的项目中有一个用于 http 客户端 class 的 class 我需要添加日志和持续时间。
这是class:
class RestClient {
public static function get($provider, $step, $url, $headers = [], $data = [])
{
return self::request(
Http::acceptJson()->withHeaders($headers),
'get',
$url,
$provider,
$step,
$data
);
}
private static function request($pendingRequest, $method, $url, $provider, $step, $data = [])
{
$startTime = microtime(true);
$client = $pendingRequest->{$method}($url, $data);
$durationTime = microtime(true) - $startTime;
if ($client->clientError() || $client->serverError()) {
HttpLog::addErrorLog(
$provider, $step, $data, $client->toException()->getMessage(), $url, $durationTime
);
if ($client->status() == 401) {
throw new InvalidTokenException();
}
if ($client->serverError()) {
throw new ServerException();
}
throw new ProviderException('ProviderException');
}
HttpLog::addLog(
$provider, $step, $client, $url, $durationTime
);
return $client->json();
}
}
我在项目的多个位置调用了 RestClient get 方法和其他方法。
调用示例:
return RestClient::get(
$this->providerName(),
'INQUIRY',
{$this->configs['base_url'],
['Authorization' => "Bearer $token",]
);
是否需要重构 RestClient class?
我建议减少参数的数量。 考虑使用链接而不是静态方法。
示例:
$restClient = new RestClient;
$restClient->provider($this->providerName());
$restClient->step("INQUIRY");
$restClient->url($this->configs['base_url']);
$restClient->headers(['Authorization' => "Bearer $token",]);
$restClient->get();
我认为链接使用起来会更方便
不知道你所说的“重构”到底是什么意思。 但如果你问的是扩展现有服务行为的最佳方式,我会说它是模式装饰器。但它需要摆脱静态方法。 此外,最好将 RestClient 注册为 DI 容器中的服务(如果您使用的是 Lumen,这里是手册 https://lumen.laravel.com/docs/5.6/container)
结果代码可能如下所示:
interface RestClientInterface
{
public function get(string $url, array $data): array;
public function post(string $url, array $data): array;
}
class RestClient implements RestClientInterface
{
private $provider;
public function __construct(ProviderInterface $provider) {
$this->provider = $provider;
}
public function get(string $url, array $data): array {
// do actual GET request using provider and return response, no additional actions
}
public function post(string $url, array $data): array {
// do actual POST request using provider and return response, no additional actions
}
}
class LoggingClient implements RestClientInterface
{
private $decorated;
public function __construct(RestClientInterface $decorated) {
$this->decorated = $decorated;
}
public function get(string $url, array $data): array {
$result = $this->decorated->get($url, $data);
// here do additional actions, logging etc
return $result;
}
public function post(string $url, array $data): array {
$result = $this->decorated->get($url, $data);
// here do additional actions, logging etc
return $result;
}
}
然后在容器中注册客户端实现并使用所需的装饰器对其进行扩展:
$this->app->bind(RestClient::class, function ($app) {
return new RestClient(new MyProvider());
});
$this->app->extend(RestClient::class, function ($decoratedClient, $app) {
return new LoggingClient($decoratedClient);
});
然后在代码中获取客户端实例:
$client = $this->app->make(RestClient::class); // or App::make(RestClient::class)
通过这种方法,您可以将服务包装在多个装饰器中,每个装饰器将负责执行一项附加操作。它提供了更大的灵活性。
$service = new DecoratorOne(new DecoratorTwo(new BasicImplementation()));