简体   繁体   English

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

[英]How to override method with inherited class in Kotlin?

I am exploring and actively using generics in production with Kotlin.我正在探索并积极在生产中使用 generics 和 Kotlin。

Kotlin + generics is a big puzzle for me, so maybe you can explain and help me understand how it works here, compared to Java. Kotlin + generics 对我来说是一个大难题,所以与 Java 相比,也许你可以在这里解释并帮助我理解它是如何工作的。

I have class AbstracApiClient (not really abstract)我有 class AbstracApiClient (不是很抽象)

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

AbstractRequestBuilder (not really abstract): AbstractRequestBuilder (不是很抽象):

open class AbstractRequestBuilder {
  ...
}

ConcreteApiClient that inherits AbstractApiClient that should override makeRequest with ConcreteRequestBuilder inherited from AbstractRequestBuilder :继承AbstractApiClientConcreteApiClient应该使用从AbstractRequestBuilder继承的ConcreteRequestBuilder覆盖 makeRequest :

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

class ConcreteRequestBuilder: AbstractRequestBuilder()

As I would have more concrete API clients.因为我会有更具体的 API 客户端。 I would like to make an abstraction that I can pass inherited concrete requests builders and override `make requests method.我想做一个抽象,我可以传递继承的具体请求构建器并覆盖`make requests 方法。

  1. I tried using it as it is but wouldn't work我尝试按原样使用它但不起作用
  2. I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R) but it won't match overriding function which I want it to be: protected override fun make request(request builder: ConcreteRequestBuilder)我试过这个表示法protected open fun <R: ApiRequestBuilder> make request(request builder: R)但它不匹配覆盖 function 我希望它是: protected override fun make request(request builder: ConcreteRequestBuilder)

What other options do I have?我还有什么其他选择? Am I missing something here?我在这里错过了什么吗?

Note: I cannot use interface or abstract classes in this scenario, so ideally I would like to find a way with inheritance and functions overriding.注意:在这种情况下,我不能使用interfaceabstract classes ,所以理想情况下,我想找到一种使用 inheritance 和函数覆盖的方法。

You can't override a method with more specific argument types, because it breaks Liskov's substitution principle :您不能使用更具体的参数类型覆盖方法,因为它违反了Liskov 的替换原则

val client: AbstractApiClient = ConcreteApiClient()

client.makeRequest(AbstractRequestBuilder())

As you can see above, the ConreteApiClient implementation has to be able to handle all possible inputs of the parent class, because it could be accessed through the parent class's API.正如您在上面看到的, ConreteApiClient实现必须能够处理父类 class 的所有可能输入,因为它可以通过父类的 API 访问。

To do what you want, you need to restrict the parent class itself via generics:要做你想做的,你需要通过 generics 限制父 class 本身:

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

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

This way, any instance of AbstractApiClient<R> has to show which type of request builder it accepts (in the type argument).这样, AbstractApiClient<R>的任何实例都必须显示它接受哪种类型的请求构建器(在 type 参数中)。 It prevents the above issue because now the parent type also carries information:它可以防止上述问题,因为现在父类型也携带信息:

// 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)我试过这个符号保护的开放乐趣 <R: ApiRequestBuilder> 发出请求(请求生成器:R)

Now regarding this attempt, it doesn't work because if you make the method generic (not the class ) it means every implementation of the method has to handle all kinds of R (NOT one R per implementation).现在关于这个尝试的实现,它不起作用,因为如果你使方法通用(不是class ),这意味着该方法的每个实现都必须处理各种R (不是一个R )。 Putting the generic on the class allows to specify the generic argument once per instance of the class.将泛型放在 class 上允许为 class 的每个实例指定一次泛型参数。

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

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