Gözlemci Kalıbı
Coddy'nin Kotlin Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 44 / 57.
gözlemci deseni, nesnelerin başka bir nesnenin, yani öznenin, olaylarına abone olmasını sağlar. Özne, gözlemcilerin bir listesini tutar ve ne yaptıklarını bilmeden bir şey olduğunda her birini bilgilendirir:
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")
}main içinde:
val acme = Stock("ACME")
acme.subscribe(Ticker())
acme.price = 120
acme.price = 95Çıktı:
ACME is now 120
ACME is now 95Kotlin'de bir gözlemci genellikle düz bir işlevdir. Özne lambdaları saklar ve her birini çağırır; bu nedenle yeni bir gözlemcinin sınıfa ihtiyacı yoktur:
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) }
}main içinde:
var clicks = 0
val save = Button("Save")
save.onClick { println("$it clicked") }
save.onClick { clicks++ }
save.click()
save.click()
println("clicks: $clicks")Çıktı:
Save clicked
Save clicked
clicks: 2Bir gözlemci dinlemeyi bırakmak isteyebilir. subscribe, gözlemciyi yeniden kaldıran bir işlev döndürürse çağıran, öznenin listesine hiç erişmeden iptal edebilir:
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) }
}main içinde:
val feed = Feed()
val cancel = feed.subscribe { println("ada reads: $it") }
feed.subscribe { println("bo reads: $it") }
feed.post("hello")
cancel()
feed.post("again")Çıktı:
ada reads: hello
bo reads: hello
bo reads: againStandart kitaplık, gözlemlenebilir bir özelliğe sahiptir. Delegates.observable(initial) { property, old, new -> ... } her atamadan sonra lambda'yı çalıştırır; 10. bölüm, kullandığı by anahtar sözcüğünü açıklar:
import kotlin.properties.Delegates
class Thermostat {
var target: Int by Delegates.observable(20) { _, old, new ->
println("target changed from $old to $new")
}
}main içinde:
val t = Thermostat()
t.target = 22
t.target = 18Çıktı:
target changed from 20 to 22
target changed from 22 to 18Görev
KolayBir WeatherStation, sağlanan TemperatureObserver arayüzünü uygulayan gözlemcileri bilgilendirir. Her bağlı gözlemciyi bilgilendiren, ancak yalnızca sıcaklık önceki okumadan farklı olduğunda (ilk okuma her zaman bilgilendirir) attach(observer), detach(observer) ve record(temp) işlevlerini yazın. Üç gözlemci yazın: Display, lines içinde display: 21 satırlarını tutar; Alarm(threshold), eşik değerinin üzerindeki sıcaklıklar için alerts içinde alarm: 31 > 30 satırlarını tutar; Stats ise summary() işlevinden min 18, max 31, updates 4 (veya no data) döndürür.
Sağlanan kod alarm eşiğini ve ardından sıcaklıkları veya detach alarm / attach alarm komutlarını okur, başlangıçta üç gözlemcinin tümünü bağlar ve son olarak görüntü satırlarını, uyarıları ve özeti yazdırır.
Kodunuz WeatherStation.kt, Display.kt, Alarm.kt, Stats.kt ve TemperatureObserver.kt dosyalarına gider. Main.kt, sağlanan giriş/çıkış kodunu içerir ve düzenlenemez.
Kendin dene
fun main() {
// Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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())
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Sınıflar ve Nesneler
Dosyalarla ÇalışmaSınıfları TanımlamaBirincil Yapıcılarinit Blokları ve Doğrulamaİkincil YapıcılarTekrar - Kütüphane Kartı4Kalıtım
Açık Sınıflar ve Alt SınıflarÜyeleri Geçersiz Kılmasuper ve YapıcılarSoyut SınıflarTekrar - Personel Dizini2Özellikler ve Kapsülleme
Özel ErişimcilerGörünürlük DeğiştiricileriÖzel Setter'larlazy ve lateinitTekrar - Banka Hesabı5Arayüzler
Arayüz BildirimleriVarsayılan MetotlarBirden Çok ArayüzTür Olarak ArayüzlerÖzet - Ödeme Yöntemleri8Generic'ler
Generic FonksiyonlarGeneric SınıflarTür Kısıtlamalarıin ve out ile VaryansTekrar - Öncelik Kuyruğu11Proje: Kütüphane Yönetimi
Kitaplar ve ÜyelerKitap Ödünç AlmaKendi başına pratik yap: Kotlin playground