はじめに
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. カスタム委譲
自分で 委譲プロパティ を実装することも可能です。
getValue と setValue を実装したクラスを用意します。
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つの主要な用途がある- インターフェースの委譲 → 実装を別のオブジェクトに任せる
- プロパティの委譲 → getter/setter を外部に任せる
- 標準の委譲機能
-
lazy(初回アクセス時に計算してキャッシュ) -
observable(変更監視) -
vetoable(変更の可否を制御)
-
-
getValue/setValueを実装すれば 独自の委譲ロジックも作れる