Menu
Coddy logo textTech

Dekoratör Deseni

Coddy'nin Kotlin Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 47 / 57.

decorator deseni, bir nesneyi aynı arayüze sahip başka bir nesneyle sararak ona davranış ekler. Decorator, sardığı nesneye yönlendirme yapar ve kendi işlevini ekler; bu nedenle decorator'lar üst üste eklenebilir:

interface Coffee {
    fun cost(): Int
    fun description(): String
}
class Espresso : Coffee {
    override fun cost() = 200
    override fun description() = "espresso"
}
class Milk(private val inner: Coffee) : Coffee {
    override fun cost() = inner.cost() + 50
    override fun description() = inner.description() + ", milk"
}
class Syrup(private val inner: Coffee) : Coffee {
    override fun cost() = inner.cost() + 30
    override fun description() = inner.description() + ", syrup"
}

main içinde:

val order = Syrup(Milk(Milk(Espresso())))
println("${order.description()}: ${order.cost()}")

Çıktı:

espresso, milk, milk, syrup: 330

Dekoratörler sonucu değiştirdiğinde sıraları önemlidir: her biri, içindeki nesnenin döndürdüğü değer üzerinde çalışır:

interface Text {
    fun render(): String
}
class Word(private val w: String) : Text {
    override fun render() = w
}
class Bracket(private val inner: Text) : Text {
    override fun render() = "[" + inner.render() + "]"
}
class Twice(private val inner: Text) : Text {
    override fun render() = inner.render() + inner.render()
}

main içinde:

println(Twice(Bracket(Word("hi"))).render())
println(Bracket(Twice(Word("hi"))).render())

Çıktı:

[hi][hi]
[hihi]

by ile bir dekoratör yalnızca değiştirdiği üyeleri yazar ve geri kalanını otomatik olarak yönlendirir:

interface Source {
    fun read(): String
    fun name(): String
}
class FileSource(private val content: String) : Source {
    override fun read() = content
    override fun name() = "notes.txt"
}
class Censored(private val inner: Source, private val word: String) : Source by inner {
    override fun read() = inner.read().replace(word, "***")
}

main içinde:

val src = Censored(FileSource("the secret plan"), "secret")
println("${src.name()}: ${src.read()}")

Çıktı:

notes.txt: the *** plan

Dekoratörler program çalışırken, örneğin bir müşterinin seçimlerinden oluşturulurken, alt sınıf kod yazılırken tek bir birleşimi sabitler. Alt sınıflar olarak üç ek, her birleşim için bir sınıf gerektirirdi; dekoratörler olarak fold bunları bir listeden üst üste ekler:

interface Coffee {
    fun cost(): Int
}
class Espresso : Coffee {
    override fun cost() = 200
}
class Extra(private val inner: Coffee, private val price: Int) : Coffee {
    override fun cost() = inner.cost() + price
}

main içinde:

val prices = mapOf("milk" to 50, "syrup" to 30, "cream" to 70)
val choices = listOf("milk", "cream", "milk")
val coffee = choices.fold<String, Coffee>(Espresso()) { c, extra -> Extra(c, prices.getValue(extra)) }
println(coffee.cost())

Çıktı:

370
challenge icon

Görev

Kolay

Pizza'lar, sağlanan Pizza arayüzünün (price() ve toppings() ile) dekoratörleri kullanılarak oluşturulur. Base'i (800, malzeme yok) ve Cheese (+150, cheese ekler), Olives (+100, olives ekler) ile her şeyi iki katına çıkaran ve malzemelerini iki kez tekrarlayan DoubleUp dekoratörlerini yazın. Ardından Base'ten başlayan ve her ad için sırayla bir dekoratörle saran build(names) işlevini yazın (cheese, olives veya double).

Sağlanan kod, virgülle ayrılmış adların bulunduğu satırları veya plain satırını okur, her pizzayı oluşturur ve 1050: cheese, olives veya 800: plain yazdırır.

Kodunuz Base.kt, Cheese.kt, Olives.kt, DoubleUp.kt, Build.kt ve Pizza.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()
    for (line in input) {
        val names = if (line == "plain") listOf() else line.split(",")
        val pizza = build(names)
        val toppings = pizza.toppings()
        println("${pizza.price()}: " + if (toppings.isEmpty()) "plain" else toppings.joinToString(", "))
    }
}
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