0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kotlin】Kotlin の委譲と `by` キーワード

Posted at

はじめに

Kotlin には 委譲 (delegation) を簡潔に書ける構文が用意されています。
これは 「あるクラスの機能を別のクラスに任せる」 デザインを簡単に実現する仕組みです。


1. 委譲とは?

委譲 (delegation) とは、あるクラスの処理を他のオブジェクトに任せる設計です。

例えば「プリンター」を考えたとき、自分で印刷ロジックを持たず、既存の Printer クラスに処理を任せるのが「委譲」です。


2. by を使ったインターフェースの委譲

Kotlin では インターフェースの実装を他のオブジェクトに委譲できます。
これを delegation pattern (委譲パターン) と呼びます。

例:インターフェースを別クラスに委譲

interface Printer {
    fun print(message: String)
}

class SimplePrinter : Printer {
    override fun print(message: String) {
        println("印刷: $message")
    }
}

// Printer の機能を委譲
class PrinterManager(printer: Printer) : Printer by printer

fun main() {
    val manager = PrinterManager(SimplePrinter())
    manager.print("Hello, Kotlin!") 
    // => 印刷: Hello, Kotlin!
}

PrinterManager 自体は print を実装していませんが、by printer によって SimplePrinter に処理が委譲されます。


3. プロパティ委譲

Kotlin では プロパティの getter/setter の実装を他に委譲することもできます。
これを Delegated Properties (委譲プロパティ) と呼びます。

代表例:lazy

val lazyValue: String by lazy {
    println("初期化中...")
    "Hello"
}

fun main() {
    println(lazyValue) // 初期化中... Hello
    println(lazyValue) // Hello(キャッシュ済み)
}

by lazy { ... }最初のアクセス時だけ計算してキャッシュする仕組みを提供します。


代表例:Delegates.observable

import kotlin.properties.Delegates

var name: String by Delegates.observable("初期値") { prop, old, new ->
    println("${prop.name}: $old -> $new")
}

fun main() {
    name = "Alice"
    name = "Bob"
}
// 出力:
// name: 初期値 -> Alice
// name: Alice -> Bob

by Delegates.observable によって、プロパティの変更を監視できます。


4. カスタム委譲

自分で 委譲プロパティ を実装することも可能です。
getValuesetValue を実装したクラスを用意します。

import kotlin.reflect.KProperty

class StringDelegate {
    private var value: String = "未設定"

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$value (from delegate)"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
        println("${property.name} を $newValue に設定します")
        value = newValue
    }
}

class User {
    var name: String by StringDelegate()
}

fun main() {
    val user = User()
    user.name = "Taro"
    println(user.name)
}
// 出力:
// name を Taro に設定します
// Taro (from delegate)

これにより、プロパティの管理ロジックを 外部クラスに切り出して再利用できます。


5. まとめ

  • by には 2つの主要な用途がある
    1. インターフェースの委譲 → 実装を別のオブジェクトに任せる
    2. プロパティの委譲 → getter/setter を外部に任せる
  • 標準の委譲機能
    • lazy(初回アクセス時に計算してキャッシュ)
    • observable(変更監視)
    • vetoable(変更の可否を制御)
  • getValue / setValue を実装すれば 独自の委譲ロジックも作れる

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?