【问题标题】:Kotlin enforce implementing class to be a supertype of another typeKotlin 强制实现类成为另一种类型的超类型
【发布时间】:2018-12-31 19:28:11
【问题描述】:

由于在 java/kotlin 中不允许多重继承,因此利用接口默认方法很有用。举个例子:

abstract class Animal { 
    fun beAnimal() { 
        println("I'm animal!") 
    } 
}
abstract class Mammal : Animal()  { 
    fun produceMilk() { 
         beAnimal().apply { println("Freesh milk!") }
    } 
}
abstract class AnimalWithBeak : Animal()  { 
    fun quack() { 
        beAnimal().apply { println("Quack!") }
    } 
}
class Platypus : ??? // I want it to both produce milk and quack!

如上所述,不允许多个基类,但我们可以使用接口:

abstract class Animal { fun beAnimal() { println("I'm animal!") } }

interface Mammal { 
    fun produceMilk() { 
        (this as Animal).beAnimal().apply { println("Freesh milk!") }
    } 
}
interface AnimalWithBeak { 
    fun quack() { 
        (this as Animal).beAnimal().apply { println("Quack!") }
    } 
}
class Platypus : Animal(), Mammal, AnimalWithBeak {
    fun bePlatypus() {
        quack() // ok
        produceMilk() // ok
    }
}

请注意,我没有 Animal 类,但我仍然想继承它,并且能够混合这些实现。上面的例子很简单,但在实际代码中它会非常有用。

问题是,不扩展Animal 的类可以实现MammalAnimalWithBeak 接口。在这种情况下,代码将被破坏,因为this as Animal 演员将失败。

所以问题 - 是否可以将接口继承限制为仅对特定类?在这种情况下,应该只允许扩展Animal 的类实现MammalAnimalWithBeak 接口。

可能不存在的抽象语法可能看起来像这样:

interface Mammal where this : Animal

但我怀疑它无效。有什么解决办法吗?

【问题讨论】:

  • Kotlin 中没有这样的功能。即使 Kotlin 有一个,Java 类仍然可以实现 Kotlin 接口,而无需考虑 Kotlin 自身的限制。

标签: inheritance kotlin default-method


【解决方案1】:

您可以使用扩展函数来完成这样的约束,但您可能不再提供接口方法。 但是,由于 Animal-class 不在您的控制之下,您可能需要添加一些其他有用的方法来使用扩展函数。

例子:

fun <T> T.produceMilk() where T : Animal, T : Mammal {
  beAnimal().apply { println("Freesh milk!") }
}

fun <T> T.quack() where T : Animal, T : AnimalWithBeak {
  beAnimal().apply { println("Quack!") }
}

fun main(args: Array<String>) {
  val myMammal = object : Mammal {} // a mammal, but not an animal
  // myMammal.produceMilk() // unresolved reference
  val myMammalAnimal = Platypus()
  myMammalAnimal.produceMilk() // works
}

您的类/接口将如下所示:

abstract class Animal { fun beAnimal() { println("I'm animal!") } }

interface Mammal
interface AnimalWithBeak 
class Platypus : Animal(), Mammal, AnimalWithBeak {
  fun bePlatypus() {
    quack() // ok
    produceMilk() // ok
  }
}

您要求的强制紧密耦合可以通过@marstrans 回答来完成。该解决方案迫使您在实现接口时始终使用动物。

【讨论】:

  • 啊,扩展功能很好用。
【解决方案2】:

您不能限制接口可以由哪些类来实现。 然而,如果你想避免强制转换,你可以给接口一个Animal 类型的属性,实现类必须重写。这至少可以确保实现类有一个可用的Animal 对象。

abstract class Animal { fun beAnimal() { println("I'm animal!") } }

interface Mammal { 
    val animal: Animal

    fun produceMilk() { 
        animal.beAnimal().apply { println("Freesh milk!") }
    } 
}

interface AnimalWithBeak {
    val animal: Animal

    fun quack() { 
        animal.beAnimal().apply { println("Quack!") }
    } 
}

class Platypus : Animal(), Mammal, AnimalWithBeak {
    override val animal = this

    fun bePlatypus() {
        quack() // ok
        produceMilk() // ok
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-22
    • 2019-12-04
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多