繁体   English   中英

通过回调参数类型紧密耦合的依赖关系

[英]Tightly coupled dependencies through callback argument types

我的示例使用 PHP,但这个概念应该适用于一般的 OOP。

我正在使用依赖注入模式来解耦我的类并允许轻松模拟和测试。 对于这个具体示例,我的示例类ApiConsumer使用 HTTP 客户端对 API 执行 HTTP 请求,该客户端通过接口注入构造函数:

class ApiConsumer {
    private $client;

    public function __construct(HttpClientInterface $client) {
        $this->client = $client;
    }
}

interface HttpClientInterface {
    public function async(string $method, string $uri, array $options, callable $success, callable $failure): void;
}

现在我的问题是那些回调和参数类型提示(在其他语言中,这将是类型声明的问题)。

该接口的一种可能实现是我的类Guzzle ,它封装了 GuzzleHttp 库,这是一个流行的 PHP 客户端库。 这个类看起来像这样:

class Guzzle implements HttpClientInterface {
    private $client;
    private $promises;

    public function __construct() {
        $this->client = new GuzzleHttp\Client;
    }

    public function async(string $method, string $uri, array $options, callable $success, callable $failure): void {
        $this->promises[] = function () use ($method, $uri, $options, $success, $failure) {
            return $this->client->requestAsync($method, $uri, $options)->then($success, $failure);
        };
    }
}

因此,它本质上将请求停放在$promises数组中,直到在某个时刻调用另一个实际运行这些请求的方法,根据请求的结果执行成功或失败回调。

当我编写这些回调函数时,这会导致问题。 为了正确键入提示实际上最终会传递给这些回调的内容,我需要直接引用 GuzzleHttp 库使用的类型。 例如,假设我在ApiConsumer类中发出 API 请求,如下所示:

    public function consumeSomeEndpoint(): void {
         $this->client->async(
             'GET', 
             'https://some.api.com/endpoint/', 
             [],
             function (Psr\Http\Message\ResponseInterface $response) {
                 var_dump($response);
             },
             function (GuzzleHttp\Exception\BadResponseException $reason) {
                 echo $reason->getResponse()->getBody();
                 throw new RuntimeException($reason->getMessage());
             },
         );
    }

ResponseInterface很好,足够通用,可以在很多地方使用(整个Psr包本质上只是提供与 HTTP 相关的接口)。 BadResponseException ,但是,具体到GuzzleHttp。 如果我想创建HttpClientInterface的替代实现,我必须实际导入 GuzzleHttp 库,这样我才能理解这些异常。 我不能在这里介绍接口,因为显然 lib 的 Exceptions 没有实现它。 BadResponseException实现的接口Psr\\Http\\Message\\RequestInterface\\RequestExceptionInterface不提供用于访问响应负载的getResponse()方法,该方法包含来自 API 的有关失败原因的潜在信息。

有没有办法解决?

是的,解决这个问题的方法是依赖一个与库没有紧密绑定的异常,并且其他替换可以抛出或实现。

幸运的是,Guzzle 就是这种情况。

GuzzleHttp\\Exception\\BadResponseException扩展了GuzzleHttp\\Exception\\RequestException ,它Psr\\Http\\Message\\RequestInterface\\RequestExceptionInterface实现了Psr\\Http\\Message\\RequestInterface\\RequestExceptionInterface

正如所见, 这里这里

/**
 * Exception when an HTTP error occurs (4xx or 5xx error)
 */
class BadResponseException extends RequestException
{ /** class omitted **}
/**
 * HTTP Request exception
 */
class RequestException extends TransferException implements RequestExceptionInterface
{ /** class omitted **}

要正确地对 ecallback 进行类型提示,您可能必须指定Psr\\Http\\Client\\ClientExceptionInterface ,因为这是 PSR 合约中最通用的一个,并且符合要求的实现可能会抛出任何扩展异常: NetworkExceptionInterfaceRequestExceptionInterface ,如前所述。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM