父类返回子类类型的函数写法

640?wx_fmt=jpeg

今天的话题很简单,分享下也许对大家可以有帮助或者有启发。

1. 背景

一看题目,有点儿晕。看个例子马上就明白了:

 
 
  1. abstract class EventBuilder() {

  2.    protected var retryLimit = 3


  3.    fun retryLimit(retryLimit: Int): EventBuilder {

  4.        this.retryLimit = retryLimit

  5.        return this

  6.    }


  7.    abstract fun build(): PollingEvent

  8. }

我们有这么一个类,一看就是要写 Builder 模式。不过由于我们的这个 Event 的类型比较多,因此希望写一个父类,来一个子类感受下:

 
 
  1. class DisposableEventBuilder : EventBuilder() {

  2.    private var delay: Long = 0L

  3.    fun delay(delay: Long): DisposableEventBuilder {

  4.        this.delay = delay

  5.        return this

  6.    }


  7.    override fun build() = object: DisposableEvent(name, delay){

  8.        override fun onDisposableEvent() {

  9.            callback.onEvent(this)

  10.        }

  11.    }

  12. }

看上去也没啥大毛病,用一下吧:

 
 
  1. DisposableEventBuilder().retryLimit(3)

  2.        .delay(60_000) // ERROR!!

  3.        .build()

我们调用完父类的 retryLimit 方法后,想要设置下 delay,结果发现没有这个方法。

“我 X,这什么玩意儿”,你嘟囔了一句。

因为返回的是父类,所以链式调用掉链子了。这就尴尬了。

2. Scala 的解法

如果这段代码用 Scala 写,那么用 this.type 就简直完美的解决了这个问题:

 
 
  1. abstract class SuperBuilder {

  2.    private var retryLimit: Int = 0


  3.    def retryLimit(retryLimit: Int): this.type = {

  4.        this.retryLimit = retryLimit

  5.        this

  6.    }

  7. }


  8. class SubBuilder extends SuperBuilder {

  9.    private var delay: Long = 0


  10.    def delay(delay: Long): SubBuilder = {

  11.        this.delay = delay

  12.        this

  13.    }

  14. }

调用时:

 
 
  1. new SubBuilder().retryLimit(3).delay(60000)

一点儿毛病都么有。

Kotlin 有这个特性吗?并没有。

3. Kotlin 的解法

Kotlin 倒也不是没有办法解决这个问题,用下泛型就好了:

 
 
  1. abstract class EventBuilder<T : EventBuilder<T>>() {

  2.    protected var retryLimit = 3


  3.    fun retryLimit(retryLimit: Int): T {

  4.        this.retryLimit = retryLimit

  5.        return this as T

  6.    }


  7.    abstract fun build(): PollingEvent

  8. }

这个泛型给父类加了一个泛型参数,这个参数则必须是当前类的子类,那么这样的话我们就可以在返回自身类型的位置返回 T 这个类型了。

子类的改动就很简单了,只需要给父类加一个泛型参数为自己的类型即可:

 
 
  1. class DisposableEventBuilder : EventBuilder<DisposableEventBuilder>() {

  2.     ...

  3. }

其他的什么也不用动,这时候我们的链式调用就没啥问题了:

 
 
  1. DisposableEventBuilder().retryLimit(3)

  2.        .delay(60_000) // OK!!

  3.        .build()

这一点上 Kotlin 和 Java 其实是一致的,所以你也可以用 Java 写出类似的代码:

 
 
  1. abstract class SuperBuilder<T extends SuperBuilder<T>> {

  2.    private int retryLimit = 0;


  3.    T retryLimit(int retryLimit) {

  4.        this.retryLimit = retryLimit;

  5.        return (T) this;

  6.    }

  7. }


  8. class SubBuilder extends SuperBuilder<SubBuilder> {

  9.    private long delay = 0;


  10.    SuperBuilder delay(long delay) {

  11.        this.delay = delay;

  12.        return this;

  13.    }

  14. }

好了,今天就先这样~~


转载请注明出处:微信公众号 Kotlin

640?wx_fmt=jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值