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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- by lazy:遅延初期化を深く学ぶ
- observableとvetoableデリゲート
- カスタムReadWritePropertyデリゲートの作成
- Preferences、Map委譲プロパティ、ロギングのデリゲート