如何在 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 方法。
- 我尝试按原样使用它,但不起作用
- 我试过这个符号
protected open fun <R: ApiRequestBuilder> make request(request builder: R)
但它不匹配我想要的覆盖函数:protected override fun make request(request builder: ConcreteRequestBuilder)
我还有哪些其他选择?我在这里遗漏了什么吗?
注意:在这种情况下我不能使用interface
或abstract 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.
的每个实例指定一次泛型参数
我正在探索并积极在 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 方法。
- 我尝试按原样使用它,但不起作用
- 我试过这个符号
protected open fun <R: ApiRequestBuilder> make request(request builder: R)
但它不匹配我想要的覆盖函数:protected override fun make request(request builder: ConcreteRequestBuilder)
我还有哪些其他选择?我在这里遗漏了什么吗?
注意:在这种情况下我不能使用interface
或abstract 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.