xin*_*aiz 6 inheritance kotlin default-method
由于 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!
Run Code Online (Sandbox Code Playgroud)
如上所述,不允许使用多个基类,但我们可以使用接口:
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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我不拥有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
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用扩展函数来完成这样的约束,但您可能不再提供接口方法。但是,由于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
}
Run Code Online (Sandbox Code Playgroud)
您的类/接口将如下所示:
abstract class Animal { fun beAnimal() { println("I'm animal!") } }
interface Mammal
interface AnimalWithBeak
class Platypus : Animal(), Mammal, AnimalWithBeak {
fun bePlatypus() {
quack() // ok
produceMilk() // ok
}
}
Run Code Online (Sandbox Code Playgroud)
您所要求的强制紧密耦合可以通过 @marstrans 答案来完成。该解决方案迫使您在实现界面时始终有一只动物。