Kotlin文法 - ネストされたクラス、Enumクラス、オブジェクト、委譲、委譲されたプロパティ


# はじめに

[Kotlin文法 - データクラス, ジェネリクス](http://qiita.com/k5n/items/18adb5c3503a54e96c22)の続き。

[Kotlin Reference](https://kotlinlang.org/dscs/reference/)のClasses and Objects章Nested Classes, Enum Classes, Objects, Delegation, Delegated Propertiesの大雑把日本語訳。かなり説明を端折ったり少し補足したりしている。

Classes and Objects章はこれでおしまい。

# ネストされたクラス

クラスはネストできる。

```kotlin
class Outer {
  private val bar: Int = 1
  class Nested {
    fun foo() = 2
  }
}

val demo = Outer.Nested().foo() // == 2
```

## 内部クラス

外側クラスのメンバにアクセスできるように、クラスの前に *inner* って付けられる。

```kotlin
class Outer {
  private val bar: Int = 1
  inner class Inner {
    fun foo() = bar // 外側のprivateなメンバにアクセスできる
  }
}

val demo = Outer().Inner().foo() // == 1
```

# Enumクラス

Enumクラスの最も一般的な使い方は型安全な列挙。

```kotlin
enum class Direction {
  NORTH, SOUTH, WEST, EAST
}
```

## 初期化

各Enum定数はEnumクラスのインスタンスなので初期化できる。

```kotlin
enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}
```

## 無名クラス

各Enum定数はそれ自身の無名クラスを宣言することもできる。

```kotlin
enum class ProtocolState {
  // WAITINGはProtoclStateを継承してsignal()をオーバーライドした無名クラスのインスタンス
  WAITING {
    override fun signal() = TALKING
  },

  TALKING {
    override fun signal() = WAITING
  };
  // ProtoclStateクラスのメンバがこの後に続くのでその前をセミコロンで区切る。
  // これはJavaのenumと一緒だね。

  abstract fun signal(): ProtocolState
}
```

## Enum定数とあそぼ

Javaと同様に *valueOf()* と *values()* メソッドが用意されている。

```kotlin
// 名前を指定して定数を取得する
EnumClass.valueOf(value: String): EnumClass
// 全ての定数の配列を取得する
EnumClass.values(): Array<EnumClass>
```

*valueOf()* で指定された名前が定義されていなかった場合、IllegalArgumentException例外が投げられる。

各Enum定数は名前と位置を取得するプロパティを持っている。

```kotlin
val name: String    // 定数名
val ordinal: Int    // 定数の宣言された順番
```

またEnum定数は *Comparable* インターフェースを実装している。比較順はEnumクラス内での定義順になる。

# オブジェクト

あるクラスをちょっとだけ変更したクラスのオブジェクトを、新しいサブクラスを宣言することなしに作りたいことがある。Javaはこれを無名内部クラスで扱う。Kotlinはこの概念を__オブジェクト式__と__オブジェクト宣言__を使ってもうちょっと一般化している。

## オブジェクト式

ある型を継承した無名クラスのオブジェクトを作るには、こう書く。

```kotlin
// MouseAdapterを継承した無名クラスのオブジェクトを作ってaddMouseListenerに渡す
window.addMouseListener(object : MouseAdapter() {
  override fun mouseClicked(e: MouseEvent) {
    // ...
  }

  override fun mouseEntered(e: MouseEvent) {
    // ...
  }
})
```

もし親クラスがコンストラクタを持つなら、適切なパラメータを渡さなければならない。インターフェースを複数実装する場合、クラス宣言と同様にコンマで区切って指定する。

```kotlin
open class A(x: Int) {
  public open val y: Int = x
}

interface B {...}

// Aクラスを継承してBインターフェースを実装する無名クラスのオブジェクトを作る
val ab = object : A(1), B {
  override val y = 15
}
```

なんも継承を指定しないオブジェクトも作れるよ。

```kotlin
val adHoc = object {
  var x: Int = 0
  var y: Int = 0
}
print(adHoc.x + adHoc.y)
```

Javaの無名内部クラスのように外側にアクセスできる（Javaだとfinalが付いてないとダメだけど、KotlinではvalでもvarでもOK）。

```kotlin
fun countClicks(window: JComponent) {
  var clickCount = 0
  var enterCount = 0

  // 無名クラスのオブジェクトを作って渡す。
  window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
      clickCount++    // この無名クラスの外側にあるclickCountにアクセスできる。
                      // しかもvalじゃなくてvarであっても。
    }

    override fun mouseEntered(e: MouseEvent) {
      enterCount++
    }
  })
  // ...
}
```

## オブジェクト宣言

Kotlinではシングルトンをとても簡単に宣言できる。

```kotlin
object DataProviderManager {
  fun registerDataProvider(provider: DataProvider) {
    // ...
  }

  val allDataProviders: Collection<DataProvider>
    get() = // ...
}
```

これは式ではなく宣言。何かの変数に入れて使ったりするものじゃない。使うときはこんな風に名前でアクセスできる。

```kotlin
// シングルトン取得用のメソッドを呼ばなくてもいいので楽チン。
DataProviderManager.registerDataProvider(dataProvider)
```

もちろん親を持てる。

```kotlin
object DefaultListener : MouseAdapter() {
  override fun mouseClicked(e: MouseEvent) {
    // ...
  }

  override fun mouseEntered(e: MouseEvent) {
    // ...
  }
}
```

NOTE: オブジェクト宣言はローカルではできない（つまり関数内ではできない）。でも他のオブジェクトや *inner* でないクラス内では宣言できる。

## コンパニオンオブジェクト

クラス内で宣言するオブジェクトには *companion* キーワードが付けられる。

```kotlin
class MyClass {
  companion object Factory {
    fun create(): MyClass = MyClass()
  }
}
```

コンパニオンオブジェクトのメンバーはオブジェクト名を指定しないで呼びだせる。

```kotlin
// MyClass.Factory.create()とは書かない。Factoryは書かない。
val instance = MyClass.create()
```

なのでオブジェクト名は省略可能。オブジェクトそのものを取得したいときは *Companion* を使う。

```kotlin
class MyClass {
  // オブジェクト名は別になくてもいいよ
  companion object {
  }
}

// オブジェクトそのものを取得したい場合はCompanionを指定する。
val x = MyClass.Companion
```

コンパニオンオブジェクトのメンバは他の言語のstaticメンバのように見えるけど、実行時においても実際のオブジェクトのインスタンスメンバである。例えばインターフェースを実装できる。

```kotlin
interface Factory<T> {
  fun create(): T
}


class MyClass {
  // Facotry<MyClass>を実装した無名クラスの無名コンパニオンオブジェクト
  companion object : Factory<MyClass> {
    override fun create(): MyClass = MyClass()
  }
}
```

けどJVM環境では、*@JvmStatic* アノテーションを付けることで、本物のstaticメソッドやフィールドとしてコンパニオンオブジェクトのメンバを生成することができる。詳細はJava interoperabilityの章を参照。

## オブジェクト式とオブジェクト宣言の意味論上の違い

オブジェクト式とオブジェクト宣言には重要な意味論(semantic)上の違いがある。

 - オブジェクト宣言は初めて利用されるときに__遅延的に(lazy)__初期化される。
 - オブジェクト式はそれが使われている場所で__即座に(immediately)__に実行（そして初期化）される。

# 委譲(Delegation)

## クラス委譲

委譲パターンは継承による実装の良い代替となることが証明されてきた[^1]。Kotlinは一切の決まり切ったコードを要求することなく、ネイティブにこれをサポートする。

[^1]: よく言われる「継承よりコンポジションを使え」というやつ。

```kotlin
interface Base {
  fun print()
}

class BaseImpl(val x: Int) : Base {
  override fun print() { print(x) }
}

// こいつはBaseインターフェースの全てのpublicメソッドをbに委譲する。
class Derived(b: Base) : Base by b

fun main() {
  val b = BaseImpl(10)
  Derived(b).print() // Derivedはbに委譲するので 10 を表示する
}
```

*by* 節は *b* が *Derived* オブジェクトの中に格納されて、コンパイラが *Base* の全てのメソッドを *b* に委譲することを示す。

# プロパティ委譲(Delegated Properties)

ある種のありがちな動作をするプロパティの実装をライブラリ化して、コードを共通化できたらとても素敵だと思わない？例えばこんなの。

 - 遅延プロパティ:  最初のアクセスで初めて計算される値
 - 観測可能(observable)プロパティ:  値に変化があったらリスナに通知される
 - マップに格納されるプロパティ:  マップ内の各値を個別のフィールドにするんじゃなく

こういう場合のためにKotlinはプロパティ委譲をサポートしている。

```kotlin
class Example {
  var p: String by Delegate()
}
```

文法はこう：val/var &lt;property name&gt;: &lt;Type&gt; by &lt;expression&gt;

このプロパティのgetter/setterは *by* の後に指定したオブジェクトに委譲される。ここで指定されるオブジェクトは getValue() と setValue() メソッドだけ持ってればいい。

```kotlin
class Delegate {
  operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
    return "$thisRef, thank you for delegating '${property.name}' to me!"
  }
 
  operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
    println("$value has been assigned to '${property.name} in $thisRef.'")
  }
}
```

Exampleインスタンスの *p* を読み出すと、Delegateクラスの *getValue()* が呼ばれる。最初の引数は *p* を読み出そうとしているExampleインスタンスで、２番目の引数は *p* そのものに関する情報（ここからプロパティ名を取り出せる）。

```kotlin
val e = Example()
println(e.p)
```

は以下を表示する。

`Example@33a17727, thank you for delegating ‘p’ to me!`

代入時には *setValue()* が呼ばれ、最初の２つの引数は *getValue()* と同じ。３つ目の引数は代入する値。

```kotlin
e.p = "NEW"
```

は以下を表示する。

`NEW has been assigned to ‘p’ in Example@33a17727.`

## プロパティ委譲の要件

プロパティ委譲のまとめをここで行う。

読み出しのみの（つまり *val* ）プロパティの場合、次のパラメータを取る *getValue()* という名前のメソッドを提供する必要がある。

 - receiver - プロパティ保持者と同じかそのサブ型でなければならない[^2]。
 - metadata - KProperty&lt;*&gt;かそのサブ型でなければならない。

また戻り値はプロパティと同じ型かそのサブ型でなければならない。

[^2]: プロパティを拡張される場合があるのでサブ型でもオッケーにしておく

変更可能(mutable)なプロパティ（つまり *var*）の場合は、それに加えて次のパラメータを取る *setValue()* という名前のメソッドを提供する必要がある。

 - receiver - getValue()と同じ
 - metadata - getValue()と同じ
 - new value - プロパティと同じかそのサブ型でなければならない

*getValue()*  や *setValue()* は、委譲クラスのメソッドか拡張メソッドとして提供される。後者はこれらのメソッドを提供していないオブジェクトにプロパティ委譲したい時に便利。どちらのメソッドも *operator* キーワードでマークされている必要がある。

## 標準ライブラリで用意されている委譲

Kotlinの標準ライブラリは幾つかの種類の便利な委譲を生成するファクトリメソッドを用意している。

### 遅延(Lazy)

*lazy()* はラムダを受け取る関数で *Lazy&lt;T&gt;* のインスタンスを返す。 *Lazy&lt;T&gt;* は遅延プロパティを実装する委譲を提供する。その委譲は、初めて *get()* が呼ばれるときに渡されたブロックを実行し、その結果を覚えておく。その後は *get()* が呼ばれるたびに覚えておいた値を返す。

```kotlin
val lazyValue: String by lazy {
    // 初めてlazyValueを取得するときにこのブロックが実行される
    println("computed!")
    "Hello"    // これを結果として覚えておき、以後はずっとこれを返す
}

fun main(args: Array<String>) {
    // 最初のアクセスなので"computed!"が表示された後、"Hello"が表示される
    println(lazyValue)
    // その後は"Hello"しか表示されない
    println(lazyValue)
}
```

### 観測可能(Observable)

*Delegates.observable()* は初期値と変更を処理するラムダの２つの引数を取る。渡されたラムダはプロパティへの代入のたびに（代入が終わった後で）呼び出される。このラムダにはプロパティ情報と前の値、新しい値の３つが引数として渡される。[^3]

```kotlin
import kotlin.properties.Delegates

class User {
    // 初期値は"<no name>"
    var name: String by Delegates.observable("<no name>") { prop, old, new ->
        // 変更のたびにこのブロックが実行される。
        // propにはプロパティ情報, oldには前の値, newには新しい値が渡される
        println("$old -> $new")
    }
}

fun main(args: Array<String>) {
    val user = User()
    user.name = "first"    // "<no name> -> first"と表示される
    user.name = "second"   // "first -> second"と表示される
}
```

*obserbale()* の代わりに *vetoable()* を使うと、プロパティへの代入前に渡したラムダが実行される。ラムダの戻り値は代入を行うかどうかを返す。これを使うと代入を拒否することができる。

[^3]: 正直期待してたのと違うなぁという印象。この例じゃ初期値与えてsetter定義するのに比べて何が便利なのかわからん。コンストラクタにDelegates.observableインスタンスを渡すとかするとプロパティの変更を外から監視できる仕組みにできるけど、監視者が１人だけじゃObserverパターンって言わないよね。別にRx使えばいんだけどさ。

### マップに格納するプロパティ

JSONパースしたりするときに、プロパティの値をマップに入れておくことってあるよね。そういう場合にはマップのインスタンスそのものを委譲先に指定できる。利用するにはマップに *getValue()* を追加する拡張をインポートする。この *getValue()* はプロパティ名をキーにしてマップから値を返す。

```kotlin
import kotlin.properties.getValue // マップにgetValue()メソッドを拡張する

class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}
```

例えばコンストラクタにこんなマップを渡すと・・・

```kotlin
val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))

println(user.name) // "John Doe"と表示される
println(user.age)  // "25"と表示される
```

これは *var* プロパティでも動作する。*Map* の代わりに *MutableMap* を利用する。あと *setValue()* を追加する拡張もインポートしてね。

```kotlin
import kotlin.properties.getValue // マップにgetValue()メソッドを拡張する
import kotlin.properties.setValue // マップにsetValue()メソッドを拡張する

class MutableUser(val map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int     by map
}
```

# 次の章へ

次は[Kotlin文法 - 関数とラムダ](http://qiita.com/k5n/items/964d765767a65cc3de5b)へGO!