Kotlinまとめ - 文法詳解 - オブジェクトからクラスへ

本記事では「バケツ」のオブジェクトを取り扱う

* データ
    * 容量
    * 現在の水量
* 振る舞い
    * 水で満たす
    * 排水する
    * 入っている水量を出力

```Kotlin
val bucket = object {
    val capacity: Int = 5

    // 現在の水量
    var quantity: Int = 0

    // バケツを水で満たす
    fun fill() {
        quantity = capacity
    }

    // 排水する
    fun drainAway() {
        quantity = 0
    }

    // 入っている水量を出力
    fun printQuantity() {
        println(quantity)
    }
}
```

# インタフェース
* このバケツオブジェクトはデータ型を持っておらず、実用には耐えない。(正確には型はあるが型名による参照ができない)
* インタフェースにより型を定義する

```Kotlin
interface Bucket

val bucket = object: Bucket {
    // バケツの容量
    val capacity: Int = 5

    // 現在の水量
    var quantity: Int = 0

    // バケツを水で満たす
    fun fill() {
        quantity = capacity
    }

    // 排水する
    fun drainAway() {
        quantity = 0
    }

    // 入っている水量を出力
    fun printQuantity() {
        println(quantity)
    }
    
    // 他のバケツに注ぐ
    // インタフェースを定義したことで、同様のインタフェースをもつオブジェクトを扱えるようになった
    fun pourTo(that: Bucket) {
        // 未実装
    }
}
```

* `Bucket`インタフェースに必要な実装を移す
    * 容量と現在の水量はgetter, setterを定義
    * `printQuantity()`は削除
    * `Bucket`を生成するメソッドを定義
* インタフェースに定義されているメソッドを実装するときは`override`キーワードをつける

```Kotlin
interface Bucket {
    fun fill()
    fun drainAway()
    fun pourTo(that: Bucket)
    
    fun getCapacity(): Int
    fun getQuantity(): Int
    fun setQuantity(quantity: Int)
}

fun createBucket(capacity: Int): Bucket = object: Bucket {

    var _quantity: Int = 0

    override fun fill() {
        setQuantity(getCapacity())
    }

    override fun drainAway() {
        setQuantity(0)
    }

    override fun pourTo(that: Bucket) {
        val thatVacuity = that.getCapacity() - that.getQuantity()
        if (getQuantity() <= thatVacuity) {
            that.setQuantity(that.getQuantity() + getQuantity())
            drainAway()
        } else {
            that.fill()
            setQuantity(getQuantity() - thatVacuity)
        }
    }

    override fun getCapacity(): Int = capacity

    override fun getQuantity(): Int = _quantity

    override fun setQuantity(quantity: Int) {
        _quantity = quantity
    }
}
```

# プロパティ
容量と現在の水量をプロパティで表現すると

```Kotlin
interface Bucket {
    val capacity: Int
    var quantity: Int

    fun fill()
    fun drainAway()
    fun pourTo(that: Bucket)
}

fun createBucket(_capacity: Int): Bucket = object: Bucket {

    override val capacity: Int = _capacity

    override var quantity: Int = 0

    override fun fill() {
        quantity = capacity
    }

    override fun drainAway() {
        quantity = 0
    }

    override fun pourTo(that: Bucket) {
        val thatVacuity = that.capacity - that.quantity
        if (quantity <= thatVacuity) {
            that.quantity += quantity
            drainAway()
        } else {
            that.fill()
            quantity -= thatVacuity
        }
    }
}
```

# クラス
* コンストラクタ経由で生成
* 継承や拡張など、強力な仕組みを使えるようになる

```Kotlin
class BucketImpl(_capacity: Int): Bucket {

    override val capacity: Int = _capacity
    
    override var quantity: Int = 0

    override fun fill() {
        quantity = capacity
    }

    override fun drainAway() {
        quantity = 0
    }

    override fun pourTo(that: Bucket) {
        val thatVacuity = that.capacity - that.quantity
        if (quantity <= thatVacuity) {
            that.quantity += quantity
            drainAway()
        } else {
            that.fill()
            quantity -= thatVacuity
        }
    }
}

val bucket: Bucket = BucketImpl(1)
```

---

[← 文法詳解 - 第一級オブジェクトとしての関数](https://qiita.com/hicka04/items/2bdad26dcd21ec970971) || [文法詳解 - クラスとそのメンバ →](https://qiita.com/hicka04/items/6f47f505d7b68ede3680)