代码之家  ›  专栏  ›  技术社区  ›  xinaiz

Kotlin强制实现类为另一个类型的超类型

  •  2
  • xinaiz  · 技术社区  · 6 年前

    由于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 类,但我仍然想将其子类化,并能够混合这些实现。上面的示例非常简单,但在实际代码中它将非常有用。

    问题是,这个类不能扩展 可以实现 Mammal AnimalWithBeak 接口。在这种情况下,代码将被破坏为 this as Animal 施放失败。

    动物 应该允许实施 哺乳动物 有喙的动物 接口。

    可能不存在的抽象语法可能是这样的:

    interface Mammal where this : Animal

    但我想这是无效的。有什么解决办法吗?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Roland    6 年前

    您可以用扩展函数来完成这样的约束,但是您可能不再提供接口方法了。 但是,作为 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
      }
    }
    

        2
  •  3
  •   marstran    6 年前

    不能约束接口可以由哪些类实现。 但是,如果希望避免强制转换,可以为接口提供类型为的属性 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
        }
    }