by ile Yetki Devri
Coddy'nin Kotlin Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 46 / 57.
Delegasyon, bir nesnenin işi devralmak yerine başka bir nesneye devretmesi anlamına gelir. Kotlin bunu doğrudan destekler: class Polite(private val inner: Greeter) : Greeter by inner, her çağrıyı inner nesnesine yönlendirerek Greeter arayüzünü uygular ve sınıf yalnızca değiştirdiği kısımları geçersiz kılar:
interface Greeter {
fun hello(name: String): String
fun bye(name: String): String
}
class English : Greeter {
override fun hello(name: String) = "Hello, $name"
override fun bye(name: String) = "Bye, $name"
}
class Polite(private val inner: Greeter) : Greeter by inner {
override fun hello(name: String) = inner.hello(name) + ", pleased to meet you"
}main içinde:
val g = Polite(English())
println(g.hello("Ada"))
println(g.bye("Ada"))Çıktı:
Hello, Ada, pleased to meet you
Bye, AdaDelegasyon, kalıtıma bir alternatiftir. Gerçekleştirmeleri final olan arayüzlerle çalışır ve delege, program çalışırken seçilen herhangi bir nesne olabilir. Bu küme her add çağrısını sayar ve diğer her şeyi normal bir MutableSet nesnesine iletir:
class CountingSet<T>(private val inner: MutableSet<T> = mutableSetOf()) : MutableSet<T> by inner {
var attempts = 0
private set
override fun add(element: T): Boolean {
attempts++
return inner.add(element)
}
}main içinde:
val tags = CountingSet<String>()
tags.add("kotlin")
tags.add("jvm")
tags.add("kotlin")
println("${tags.size} tags after ${tags.attempts} adds, contains jvm: ${"jvm" in tags}")Çıktı:
2 tags after 3 adds, contains jvm: trueTemsilci özellikler, bir özelliğin alıcı ve ayarlayıcısını yine by kullanarak başka bir nesneye devreder. 2. bölümdeki lazy bu tür bir temsilcidir; bir eşlem de başka bir temsilci olabilir: her özellik, kendi adıyla olan girdiyi okur:
class User(values: Map<String, Any?>) {
val name: String by values
val age: Int by values
}main içinde:
val u = User(mapOf("name" to "Ada", "age" to 36))
println("${u.name} is ${u.age}")Çıktı:
Ada is 36Kendi özellik temsilcinizi yazabilirsiniz: operator fun getValue içeren bir sınıf ve bir var için ayrıca setValue. Kotlin, özelliğin her okunması ve yazılması için bunları çağırır. Bu temsilci, atanan her metni kırpar ve değişiklikleri sayar:
import kotlin.reflect.KProperty
class Trimmed {
private var value = ""
var changes = 0
operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
value = newValue.trim()
changes++
}
}
class Form {
val nameField = Trimmed()
var name: String by nameField
}main içinde:
val form = Form()
form.name = " Ada "
form.name = "Ada L. "
println("[${form.name}] after ${form.nameField.changes} changes")Çıktı:
[Ada L.] after 2 changesGörev
Kolayput, get ve keys içeren Storage arayüzü ve bunun MapStorage uygulaması sağlanmıştır. Sınıf devrini kullanarak, her biri yalnızca put metodunu geçersiz kılan iki dekoratör yazın: LoggingStorage(inner), salt okunur log listesine put a=1 kaydını ekler ve çağrıyı iletir; LimitedStorage(inner, max) ise max anahtar mevcut olduğunda yeni bir anahtar eklemeyi reddeder (false döndürür), ancak mevcut anahtarların güncellenmesine yine izin verir. Diğer her şey by ile iletilir.
Sağlanan kod, bir MapStorage'ı LoggingStorage içine sarar ve ilk satır pozitif bir sınır olduğunda bunu bir LimitedStorage içine sarar. put a 1, get a ve keys komutlarını çalıştırarak ok, refused, değeri veya missing ile anahtar listesini yazdırır ve son olarak log: put a=1, ... yazdırır.
Kodunuz LoggingStorage.kt, LimitedStorage.kt, Storage.kt ve MapStorage.kt dosyalarına yazılmalıdır. Main.kt, sağlanan girdi/çıktı 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 base = MapStorage()
val logging = LoggingStorage(base)
val limit = input[0].toInt()
val storage: Storage = if (limit > 0) LimitedStorage(logging, limit) else logging
for (cmd in input.drop(1)) {
val p = cmd.split(" ")
when (p[0]) {
"put" -> println(if (storage.put(p[1], p[2])) "ok" else "refused")
"get" -> println(storage.get(p[1]) ?: "missing")
else -> println(storage.keys())
}
}
println("log: " + logging.log.joinToString(", ").ifEmpty { "empty" })
}
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