如何在 Kotlin 中用继承的 class 覆盖方法?

How to override method with inherited class in Kotlin?

我正在探索并积极在 Kotlin 的生产中使用泛型。

Kotlin + 泛型对我来说是个大难题,所以也许你可以解释并帮助我理解它是如何工作的,与 Java 相比。

我有classAbstracApiClient(不是很抽象)

class AbstracApiClient {
  
  open protected fun makeRequest(requestBuilder: AbstractRequestBuilder) {
    // ... 
  }
}

AbstractRequestBuilder(不是很抽象):

open class AbstractRequestBuilder {
  ...
}

ConcreteApiClient 继承 AbstractApiClient 应该用 ConcreteRequestBuilder 覆盖 makeRequest 继承自 AbstractRequestBuilder:

class ConcreteApiClient: AbstractApiClient() {
  
  protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
    // ... 
  }
}

class ConcreteRequestBuilder: AbstractRequestBuilder()

因为我会有更具体的 API 客户。我想做一个抽象,我可以传递继承的具体请求构建器并覆盖 `make requests 方法。

  1. 我尝试按原样使用它,但不起作用
  2. 我试过这个符号 protected open fun <R: ApiRequestBuilder> make request(request builder: R) 但它不匹配我想要的覆盖函数:protected override fun make request(request builder: ConcreteRequestBuilder)

我还有哪些其他选择?我在这里遗漏了什么吗?

注意:在这种情况下我不能使用interfaceabstract classes,所以理想情况下我想找到一种继承和函数覆盖的方法。

您不能覆盖具有更具体参数类型的方法,因为它会破坏 Liskov's substitution principle:

val client: AbstractApiClient = ConcreteApiClient()

client.makeRequest(AbstractRequestBuilder())

正如您在上面看到的,ConreteApiClient 实现必须能够处理父级 class 的所有可能输入,因为它可以通过父级 class' s API.

为了做你想做的事,你需要通过泛型限制父 class 本身:

open class AbstractApiClient<R : AbstractRequestBuilder> {
  
  open protected fun makeRequest(requestBuilder: R) {
    // ... 
  }
}

class ConcreteApiClient: AbstractApiClient<ConcreteRequestBuilder>() {
  
  protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
    // ... 
  }
}

这样,AbstractApiClient<R> 的任何实例都必须显示它接受哪种类型的请求生成器(在类型参数中)。它可以防止上述问题,因为现在父类型还带有信息:

// doesn't compile
val client: AbstractApiClient<AbstractRequestBuilder> = ConcreteApiClient() 

// this compiles
val client: AbstractApiClient<ConcreteRequestBuilder> = ConcreteApiClient()

I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R)

现在关于此尝试,它不起作用,因为如果您使 方法 通用(而不是 class ) 这意味着该方法的每个实现都必须处理 所有 R (每个实现不是一个 R )。将泛型放在 class 上允许为 class.

的每个实例指定一次泛型参数