Swift - 使用针对不同 <T> 类型的通用方法实现协议

Swift - implement protocol with generic method for different <T> types

我有一个 Client 协议,如下所示:

protocol Client {
  func get<T>(_ url: String) -> Promise<T>
}

现在,当我尝试实施它时,问题就开始了。我想要两种类型的客户端:AlamofireClient 和 MockClient(也许将来会更多,比如 ErrorClient 等,但让我们从简单的开始)

所以我需要这样的东西:

final class AlamofireClient: Client {
   func get<T: Decodable>(_ url: String) -> Promise<T> {
        (...)
   }
}

和:

final class MockClient: Client {
   func get<T: Mockable>(_ url: String) -> Promise<T> {
            return Promise { seal in
               seal.fulfill(T.mock())
        }
   }
}

这里是应用程序中的每个实体都将实现的简单 Mockable 接口:

public protocol Mockable {
    static func mock() -> Self
}

但我总是得到错误:

Type 'MockClient' does not conform to protocol 'Client'
Type 'AlamofireClient' does not conform to protocol 'Client'

那是因为它与 不同

有什么优雅的方法可以解决这个问题吗?我无法为这个问题找到一个优雅的解决方案。也许整个想法很糟糕?我也试过用 PAT 解决问题,但也没有成功。

按照您的编写方式,通过遵守客户端协议,您必须使用通用的、不受约束的参数 T 来实现一个函数 get。在提供的示例实现中,您向泛型参数 T 添加了类型约束,这与协议中的函数不匹配。

解决此问题的方法不止一种。请记住,您说过所有实体都将符合 Mockable,需要对您提供的代码进行最少更改的解决方案是使用协议组合来强制所有参数 T 都符合 [=16] =] 和 Mockable.

protocol Client {
  func get<T: Decodable & Mockable>(_ url: String) -> Promise<T>
}

在您的客户中,您将完全按照编写的方式实现该功能。

现在,在您的 MockClient 中,您可以调用 T.mock(),并且在您的实际实现中,您可以根据需要将 T 视为 Decodable。当然,这现在要求即使您的模拟参数也符合 Decodable,但我认为您的模拟参数将相当轻量级,因此这不会成为问题。