有没有办法用声明类型的子类型覆盖抽象属性?

时间:2019-12-18 16:31:10

标签: kotlin polymorphism abstract-class

请考虑以下示例:我有一个Animal的抽象类,每个动物都有一张嘴,但是由于每个动物的嘴都不同,所以该嘴类也很抽象:

abstract class Animal {
    var numberLegs: Int = 4
    var mouth: Mouth? = null
} 

abstract class Mouth {
    abstract fun makeSound()
}

我现在可以创建一个Dog和一个DogMouth:

class Dog: Animal() {
    override var mouth: Mouth = DogMouth()
}

class DogMouth: Mouth() {
    override fun makeSound() {
        println("Bark!")
    }
}

但是,这还允许我为狗指定其他类型的嘴,例如:

class CatMouth: Mouth() {
    override fun makeSound() {
        println("Meow!")
    }
}

fun main() {
    val dog = Dog()
    dog.mouth.makeSound()   // will print "Bark!"
    dog.mouth = CatMouth()  // I don't want this to work
    dog.mouth.makeSound()   // will print "Meow!"
}

设置override var mouth: DogMouth = DogMouth()无效。

如何确保狗只具有DogMouths(以及其他狗的身体部位)?

1 个答案:

答案 0 :(得分:0)

类似的问题已解决herehere。 解决方案是使用通用参数:

abstract class Animal<MouthType: Mouth> {
    var numberLegs: Int = 4
    abstract var mouth: MouthType
} 

class Dog: Animal<DogMouth>() {
    override var mouth: DogMouth = DogMouth()
}

这会使dog.mouth = CatMouth()因类型不匹配而失败。

随着身体部位的增加,需要添加额外的泛型:

abstract class Animal<MouthType: Mouth, EarType: Ear, TailType: Tail> {
    var numberLegs: Int = 4
    abstract var mouth: MouthType
    abstract var ear: EarType
    abstract var tail: TailType
}