由于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
的类可以实现Mammal
和AnimalWithBeak
接口。在这种情况下,代码将被破坏,因为this as Animal
强制转换将失败。
那么问题来了——是否有可能只将接口继承约束到特定的类?在这种情况下,应该只允许扩展Animal
的类实现Mammal
和AnimalWithBeak
接口。
可能不存在的抽象语法可能看起来像这样:
interface Mammal where this : Animal
但我怀疑这是无效的。有什么解决方案吗?
您不能约束接口可以由哪些类实现。但是,如果希望避免强制转换,可以为接口提供类型为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
}
}
您可以使用扩展函数来实现这样的约束,但您可能不再提供接口方法。但是,由于Animal
-类不在您的控制之下,您可能需要添加一些其他有用的方法,以便使用扩展函数。
示例:
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答案来完成。该解决方案迫使您在实现接口时始终使用动物。