Kotlinのきほん インターフェイス編

はじめに

SpringFesta2018に参加してKotlinの話をいたるところで聞き、Kotlinを今日から勉強していこうと思います。参考にする本はこれ。

Kotlinイン・アクション

Kotlinイン・アクション

Kotlinを開発した人が書いているので言語の目指すところや、奥深い内容を理解できるんじゃないかなと思います。時間があったらKotlinの書き方だけではなくて思想や今後の動きについてもまとめていきたいと考えています。

私は物忘れが激しいのでチートシートも見ながら進めます。

セットアップ 

開発環境は以下の通り。

IntelliJはCommunity EditionでもKotlinの開発を行うことができます。

Kotlinのクラスと愉快な仲間たち

こんな種類があります。

  • クラス
  • 抽象クラス
  • インターフェイス
  • データクラス
  • 内部クラス
  • ネストクラス
  • シールドクラス
  • クラス委譲
  • コンパニオンオブジェクト

なかなか多いです。ので、今回はインターフェイスを中心に取り上げます。

インターフェイス

Kotlin公式サイトのインターフェイスに関するドキュメントはこれ

interface User {
    fun activate(): Boolean
}

基本的にはJavaと同じです。これを実装するクラスには、宣言されているメソッドを実装する義務が発生します。でなければコンパイルエラーになります。

インターフェイスのメソッド宣言を実装する場合、overrideキーワードを付けることは必須です。Javaのようにアノテーションでつけなくても怒られないなんてことはありません。

class Employee(
        val name: String,
        val postalCode: String
) : User {

    // 必ずoverrideはつけないといけない
    override fun activate(): Boolean {
        return true
    }

}

インターフェイスにプロパティを宣言

Javaと違うところは、インターフェイスにプロパティを宣言できることです。

interface User {
    fun activate(): Boolean
    val name: String
}

実際にはインターフェイスが値を持つのではなくて、これを実装するクラスが値をもつことになります。なので、ここで宣言しているのは実装クラスはnameの値を取得する手段を持たなくてはならないと言うことになります。実際に、このインターフェイスを実装するクラスは以下のようになります。

class Employee(
        override val name: String, // nameの値をセット
        private val postalCode: String
) : User {

    override fun activate(): Boolean {
        println("activate $name")
        return true
    }

}

Employeeのプライマリコンストラクタに対してoverrideキーワードを使用し、nameを持たせました。こうすることでEmployeeUserの宣言内容を満たすことが出来ます。

fun main(args: Array<String>) {
    val user : User = Employee(name = "BookStore", postalCode = "12345")
    println(user.name)
    println(user.activate())
}
// 出力
BookStore
activate BookStore
true

インターフェイスのデフォルト実装と衝突

Javaは8からインターフェイスに対してデフォルト実装をすることができるようになりました。Kotlinも出来ます。

interface User {
    fun activate(): Boolean {
        println("Activate By User")
        return true
    }
}

ですが、同時に以下のような同じデフォルトメソッドを持つインターフェイスがあり、同時に実装するとどうなるかと言うと、オーバーライドが強制されます。

interface Actionable {
    fun activate(): Boolean {
        println("Activate By Actionable")
        return true
    }
}

class Employee(
        val name: String,
        val postalCode: String
) : User , Actionable {

    // 必ずオーバーライドしなくてはいけない
    override fun activate(): Boolean {
        return true
    }

}

理由は当然で、このままだとどちらのメソッドを呼び出せばいいかわからないからですね。ただ、このようにインターフェイスのデフォルト実装が衝突するというのはアーキテクチャ的にいけてない場合なんじゃないかと思います。

ちなみに、デフォルト実装を呼び出すことは出来ます。

class Employee(
        val name: String,
        val postalCode: String
) : User , Actionable {

    override fun activate(): Boolean {
        super<User>.activate()
        super<Actionable>.activate()
        return true
    }

}

おわりに

Kotlinを知るたびに「KotlinってJavaが少し便利になったやつでしょ?」と思っていた頃の自分を殴りたいです。次は多分抽象クラスとクラスのことについて書きます。