Pola Observer
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Kotlin di Coddy. Pelajaran 44 dari 57.
Pola observer memungkinkan object berlangganan pada peristiwa dari object lain, yaitu subject. Subject menyimpan list observer dan memberi tahu setiap observer saat sesuatu terjadi, tanpa mengetahui apa yang mereka lakukan terhadapnya:
interface PriceListener {
fun priceChanged(symbol: String, price: Int)
}
class Stock(val symbol: String) {
private val listeners = mutableListOf<PriceListener>()
var price = 0
set(value) {
field = value
for (l in listeners) l.priceChanged(symbol, value)
}
fun subscribe(l: PriceListener) { listeners.add(l) }
}
class Ticker : PriceListener {
override fun priceChanged(symbol: String, price: Int) = println("$symbol is now $price")
}Di dalam main:
val acme = Stock("ACME")
acme.subscribe(Ticker())
acme.price = 120
acme.price = 95Output:
ACME is now 120
ACME is now 95Dalam Kotlin, observer biasanya berupa fungsi biasa. Subject menyimpan lambda dan memanggil masing-masing, jadi observer baru tidak memerlukan class:
class Button(val label: String) {
private val handlers = mutableListOf<(String) -> Unit>()
fun onClick(handler: (String) -> Unit) { handlers.add(handler) }
fun click() { for (h in handlers) h(label) }
}Di dalam main:
var clicks = 0
val save = Button("Save")
save.onClick { println("$it clicked") }
save.onClick { clicks++ }
save.click()
save.click()
println("clicks: $clicks")Output:
Save clicked
Save clicked
clicks: 2Seorang observer mungkin ingin berhenti mendengarkan. Jika subscribe mengembalikan fungsi yang menghapus observer lagi, pemanggil dapat membatalkan tanpa mengakses daftar milik subject:
class Feed {
private val readers = mutableListOf<(String) -> Unit>()
fun subscribe(reader: (String) -> Unit): () -> Unit {
readers.add(reader)
return { readers.remove(reader) }
}
fun post(text: String) { for (r in readers.toList()) r(text) }
}Di dalam main:
val feed = Feed()
val cancel = feed.subscribe { println("ada reads: $it") }
feed.subscribe { println("bo reads: $it") }
feed.post("hello")
cancel()
feed.post("again")Output:
ada reads: hello
bo reads: hello
bo reads: againStandard library menyediakan property yang dapat diamati. Delegates.observable(initial) { property, old, new -> ... } menjalankan lambda setelah setiap penetapan; bab 10 menjelaskan kata kunci by yang digunakannya:
import kotlin.properties.Delegates
class Thermostat {
var target: Int by Delegates.observable(20) { _, old, new ->
println("target changed from $old to $new")
}
}Di dalam main:
val t = Thermostat()
t.target = 22
t.target = 18Output:
target changed from 20 to 22
target changed from 22 to 18Tantangan
MudahWeatherStation memberi tahu pengamat yang mengimplementasikan TemperatureObserver yang disediakan. Tulis attach(observer), detach(observer), dan record(temp), yang memberi tahu setiap pengamat yang terpasang, tetapi hanya saat suhu berbeda dari pembacaan sebelumnya (pembacaan pertama selalu memicu pemberitahuan). Tulis tiga pengamat: Display menyimpan baris display: 21 di lines, Alarm(threshold) menyimpan baris alarm: 31 > 30 di alerts untuk suhu yang melebihi ambang batas, dan Stats mengembalikan min 18, max 31, updates 4 dari summary() (atau no data).
Code yang disediakan membaca ambang batas alarm, lalu suhu atau detach alarm / attach alarm, memasang ketiga pengamat di awal, lalu mencetak baris display, peringatan, dan ringkasan.
Letakkan kodemu di WeatherStation.kt, Display.kt, Alarm.kt, Stats.kt, dan TemperatureObserver.kt. Main.kt berisi code input/output yang disediakan dan tidak boleh diedit.
Coba sendiri
fun main() {
// Kode input/output yang disediakan: biarkan apa adanya
val input = generateSequence(::readLine).toList()
val station = WeatherStation()
val display = Display()
val alarm = Alarm(input[0].toInt())
val stats = Stats()
station.attach(display)
station.attach(alarm)
station.attach(stats)
for (cmd in input.drop(1)) {
when (cmd) {
"detach alarm" -> station.detach(alarm)
"attach alarm" -> station.attach(alarm)
else -> station.record(cmd.toInt())
}
}
for (line in display.lines) println(line)
for (line in alarm.alerts) println(line)
println(stats.summary())
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1class dan object
Bekerja dengan fileMendefinisikan classKonstruktor utamaBlok init dan validasiKonstruktor sekunderRingkasan: Kartu Perpustakaan2property dan Enkapsulasi
Accessor KustomModifier VisibilitasSetter Privatlazy dan lateinitRingkasan: Rekening Bank5Interface
Mendeklarasikan Interfacemethod DefaultBeberapa InterfaceInterface sebagai TipeUlasan: Metode Pembayaran11Proyek: Pengelolaan Perpustakaan
Buku dan AnggotaPeminjaman BukuLatihan sendiri: Playground Kotlin