※ 本記事は感想100%です。

開発環境

Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.5.10

抽象クラス

abstract class Animal {
    abstract val name: String
    abstract fun bark()
}

class Dog(override val name: String) : Animal() {
    override fun bark() {
        println("AO~N")
    }
}

fun main() {
    val dog = Dog(name = "INU")
    dog.bark()  // AO~N
}

interface

interface Animal {
    val name: String
    fun bark()
}

class Dog(override val name: String) : Animal {
    override fun bark() {
        println("AO~N")
    }
}

fun main() {
    val dog = Dog(name = "INU")
    dog.bark()  // AO~N
}

 

違いが分からない。
明確な棲み分けはどうなるんだ?
色々試してみる。

どちらもエラーが出ると思うが、具象化したクラスを作る前に実体化を試みる。

そのまま実体化: 抽象クラス (できない)

エラー。

abstract class Animal {
    abstract val name: String
    abstract fun bark()
}

class Dog(override val name: String) : Animal() {
    override fun bark() {
        println("AO~N")
    }
}

fun main() {
    // Cannot create an instance of an abstract class
    val animal = Animal(name = "hoge")
    dog.bark()  // AO~N
}

「抽象クラスのインスタンスを作成できません」
そういう仕組みなのだろう。

そのまま実体化: interface (できない)

エラー。

interface Animal {
    val name: String
    fun bark()
}

class Dog(override val name: String) : Animal {
    override fun bark() {
        println("AO~N")
    }
}

fun main() {
    // Interface Animal does not have constructors
    val animal = Animal(name = "hoge")
    animal.bark()
}

「Interface Animalにはコンストラクタがありません」
interface はクラスではない → クラスでないのでコンストラクタがない、という理解。

 

もう少し試す。

複数具象: 抽象クラス (できない)

エラー。

abstract class Animal {
    abstract val name: String
    abstract fun bark()
}

abstract class Plant {
    abstract var hitPoint: Int
    abstract fun grow(water: Int)
}

// Only one class may appear in a supertype list
class DogPlant(override val name: String, override var hitPoint: Int) : Animal(), Plant() {
    override fun bark() {
        println("AO~N")
    }

    override fun grow(water: Int) {
        hitPoint += water
    }
}

fun main() {
    val dog = DogPlant(name = "INU_FLOWER", hitPoint = 100)
    dog.bark()
}

そもそも複数継承というよりかは、複数具象が適切な日本語かもしれない。
抽象クラスの具象化に際し、複数の抽象クラスからは具象化できない。

複数具象: interface

interface Animal {
    val name: String
    fun bark()
}

interface Plant {
    var hitPoint: Int
    fun grow(water: Int)
}

class DogPlant(override val name: String, override var hitPoint: Int) : Animal, Plant {
    override fun bark() {
        println("AO~N")
    }

    override fun grow(water: Int) {
        hitPoint += water
    }

    fun showHitPoint() {
        println("%s's HitPoint: %d".format(name, hitPoint))
    }
}

fun main() {
    val dogPlant = DogPlant(name = "INU_FLOWER", hitPoint = 100)
    dogPlant.grow(15)
    dogPlant.showHitPoint()  // INU_FLOWER's HitPoint: 115
}

こっちはできた。

まとめ

抽象クラス interface
単一具象 o o
そのまま実体化 x x
複数具象 x o

 

ここまでの理解で、複数ある抽象を具象化させるためには interface を使う必要がある、というイメージに落ち着いた。

Swift (iOS) で例えると、「この ViewController には共通の ViewController のクラスを継承させたい。また、MVPを採用しているから Presenter の Output の protocol を ViewController に準拠させたい」という場合は、ViewController に対して2つのinterface を具象化させる必要がある? もう少し見てみる。