Menu
Coddy logo textTech

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, Ada

Delegasyon, 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: true

Temsilci ö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 36

Kendi ö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 changes
challenge icon

Görev

Kolay

put, 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" })
}
quiz iconKendini test et

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

Kendi başına pratik yap: Kotlin playground