Делегаты observable и vetoable
Реагируйте на изменения свойств с помощью observable и условно отклоняйте их с помощью vetoable.
«Делегаты observable и vetoable» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения 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
}Запуск обновлений пользовательского интерфейса
Наблюдаемые делегаты отлично подходят для запуска обновления пользовательского интерфейса при изменении базового свойства без полной настройки LiveData.
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 можно объединять вручную: напишите собственный делегат, который вызывает 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 по умолчанию не являются потокобезопасными. При параллельном доступе защищайте изменения с помощью мьютекса или выполняйте внешнюю синхронизацию.
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/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Делегаты observable и vetoable»?
Реагируйте на изменения свойств с помощью observable и условно отклоняйте их с помощью vetoable. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Делегаты observable и vetoable»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- by lazy: подробный разбор отложенной инициализации
- Делегаты observable и vetoable
- Написание пользовательского делегата ReadWriteProperty
- Делегаты для настроек, свойств на основе карт и ведения журнала