由于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
但是我怀疑这是无效的。有解决方案吗?
答案 0 :(得分:3)
您不能限制接口可以实现的类。
但是,如果要避免强制转换,则可以为接口提供类型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
}
}
答案 1 :(得分:3)
您可以使用扩展功能来完成这种约束,但是您可能再也不能提供接口方法了。
但是,由于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答案来完成。该解决方案迫使您在实现接口时总是怀有幻想。