0Pricing
Kotlin Academy · レッスン

observableとvetoableデリゲート

observableでプロパティの変更に反応し、vetoableで条件に応じて変更を拒否します。

「observableとvetoableデリゲート」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

プロパティデリゲートのおさらい

Kotlinのプロパティデリゲートを使うと、別のオブジェクトにgetValueとsetValueの処理を委譲できます。Delegates.observableとDelegates.vetoableは、標準ライブラリに組み込まれたデリゲートです。

import kotlin.properties.Delegates
var name: String by Delegates.observable("initial") { prop, old, new ->
    println("${prop.name}: $old -> $new")
}
fun main() { name = "Alice"; name = "Bob" }

observableの構文

observableは初期値とコールバックを受け取ります。コールバックは変更の後に呼び出され、プロパティ、古い値、新しい値を受け取ります。

import kotlin.properties.Delegates
var score: Int by Delegates.observable(0) { _, old, new ->
    println("Score changed from $old to $new")
}
fun main() {
    score = 10
    score = 25
    score = 0
}

UI更新のトリガー

Observableデリゲートは、完全なLiveDataの設定を行わずに、元になるプロパティの変更時にUIの更新をトリガーするのに適しています。

import kotlin.properties.Delegates
class ViewModel {
    var title: String by Delegates.observable("Loading") { _, _, new ->
        println("Render: $new") // pretend this updates UI
    }
}
fun main() {
    val vm = ViewModel()
    vm.title = "Home"
    vm.title = "Settings"
}

vetoableの構文

vetoableは代入の前にコールバックを呼び出します。コールバックがfalseを返すと、新しい値は拒否され、古い値が保持されます。

import kotlin.properties.Delegates
var age: Int by Delegates.vetoable(0) { _, old, new ->
    new >= 0 // reject negative ages
}
fun main() {
    age = 25; println(age)  // 25
    age = -1; println(age)  // 25 (rejected)
    age = 30; println(age)  // 30
}

vetoableによる検証の組み込み

vetoableを使用すると、外部の検証ロジックなしで、プロパティレベルにドメインの不変条件を適用できます。

import kotlin.properties.Delegates
var email: String by Delegates.vetoable("") { _, _, new ->
    new.contains("@")
}
fun main() {
    email = "user@example.com"; println(email) // set
    email = "invalid";          println(email) // still previous
}

observableによる変更のログ出力

監査ログにはobservableを使用します。ビジネスロジックに手を加えず、状態の遷移をすべて自動的に記録できます。

import kotlin.properties.Delegates
val log = mutableListOf<String>()
var status: String by Delegates.observable("IDLE") { _, old, new ->
    log.add("$old -> $new")
}
fun main() {
    status = "RUNNING"
    status = "DONE"
    println(log)
}

クラス内のobservable

どちらのデリゲートも、他のプロパティと同じようにクラス本体内で使用できます。

import kotlin.properties.Delegates
class Counter {
    var count: Int by Delegates.observable(0) { _, old, new ->
        if (new > old) println("Incremented to $new")
        else println("Decremented to $new")
    }
}
fun main() {
    val c = Counter()
    c.count = 5
    c.count = 3
}

範囲制約にvetoableを使う

vetoableを使用して、数値プロパティを有効な範囲に制限できます。

import kotlin.properties.Delegates
var volume: Int by Delegates.vetoable(50) { _, _, new ->
    new in 0..100
}
fun main() {
    volume = 80;  println(volume) // 80
    volume = 150; println(volume) // 80 (rejected)
    volume = 0;   println(volume) // 0
}

デリゲートのチェーン

observableを内部で呼び出すカスタムデリゲートを記述すれば、デリゲートを手動で組み合わせ、各ステップに追加のロジックを加えられます。

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class LoggedDelegate<T>(initial: T) : ReadWriteProperty<Any?, T> {
    private var value: T = initial
    override fun getValue(t: Any?, p: KProperty<*>) = value
    override fun setValue(t: Any?, p: KProperty<*>, v: T) {
        println("Setting ${p.name} = $v"); value = v
    }
}
var x: Int by LoggedDelegate(0)
fun main() { x = 10; x = 20 }

スレッドセーフ性に関する注意

observableもvetoableも、デフォルトではスレッドセーフではありません。同時アクセスがある場合は、Mutexで変更を保護するか、外部で同期してください。

import kotlin.properties.Delegates
// Not thread-safe as-is:
var sharedState: String by Delegates.observable("start") { _, old, new ->
    println("$old -> $new")
}
// In coroutines, wrap access with Mutex if needed

実践パターン:フォーム検証

宣言的なフォーム検証では、フィールドごとにvetoableを使用します。各フィールドが代入時に自動的に自身を検証します。

import kotlin.properties.Delegates
data class Form(
    var username: String = "",
    var password: String = ""
) {
    var validUsername: String by Delegates.vetoable("") { _,_,v -> v.length >= 3 }
    var validPassword: String by Delegates.vetoable("") { _,_,v -> v.length >= 8 }
}
fun main() {
    val f = Form()
    f.validUsername = "ab";       println(f.validUsername) // ""
    f.validUsername = "alice";    println(f.validUsername) // "alice"
    f.validPassword = "short";    println(f.validPassword) // ""
    f.validPassword = "secure123";println(f.validPassword) // "secure123"
}

クイックチェック

vetoableはいつコールバックを呼び出しますか?

振り返り

observableは変更のたびに後から通知し、vetoableは代入前に実行され、新しい値を拒否できます。どちらも、外部ライブラリなしでログ出力、検証、リアクティブなプロパティパターンを実現するのに適しています。

よくある質問

「observableとvetoableデリゲート」レッスンは無料ですか?

はい。「observableとvetoableデリゲート」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「observableとvetoableデリゲート」で何を学びますか?

observableでプロパティの変更に反応し、vetoableで条件に応じて変更を拒否します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「observableとvetoableデリゲート」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. by lazy:遅延初期化を深く学ぶ
  2. observableとvetoableデリゲート
  3. カスタムReadWritePropertyデリゲートの作成
  4. Preferences、Map委譲プロパティ、ロギングのデリゲート
← Kotlin Academyに戻る