Pattern Decorator
Fa parte della sezione Programmazione orientata agli oggetti del percorso Kotlin di Coddy. Lezione 47 di 57.
Il pattern decorator aggiunge comportamento a un oggetto racchiudendolo in un altro oggetto con la stessa interfaccia. Il decorator inoltra le chiamate all’oggetto che racchiude e aggiunge la propria parte, così è possibile impilare più decorator:
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"
}All’interno di main:
val order = Syrup(Milk(Milk(Espresso())))
println("${order.description()}: ${order.cost()}")Output:
espresso, milk, milk, syrup: 330Quando i decoratori modificano il risultato, il loro ordine è importante: ognuno lavora su ciò che ha restituito l'oggetto al suo interno:
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()
}All'interno di main:
println(Twice(Bracket(Word("hi"))).render())
println(Bracket(Twice(Word("hi"))).render())Output:
[hi][hi]
[hihi]Con by, un decoratore scrive solo i membri che modifica e inoltra automaticamente gli altri:
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, "***")
}All'interno di main:
val src = Censored(FileSource("the secret plan"), "secret")
println("${src.name()}: ${src.read()}")Output:
notes.txt: the *** planI decorator vengono combinati mentre il programma è in esecuzione, per esempio in base alle scelte di un cliente, mentre una sottoclasse fissa una combinazione quando viene scritto il codice. Tre extra come sottoclassi richiederebbero una classe per ogni combinazione; come decorator, fold li accumula da una lista:
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
}All'interno di main:
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())Output:
370Sfida
FacileLe pizze vengono composte usando decoratori dell'interfaccia fornita Pizza (con price() e toppings()). Scrivi Base (800, senza condimenti) e i decoratori Cheese (+150, aggiunge cheese), Olives (+100, aggiunge olives) e DoubleUp, che raddoppia il prezzo di tutto ciò che contiene e ripete i suoi condimenti due volte. Poi scrivi build(names), che parte da Base e lo avvolge con un decoratore per ogni nome, nell'ordine (cheese, olives o double).
Il codice fornito legge righe con nomi separati da virgole, oppure plain, crea ogni pizza e stampa 1050: cheese, olives o 800: plain.
Il tuo codice va inserito in Base.kt, Cheese.kt, Olives.kt, DoubleUp.kt, Build.kt e Pizza.kt. Main.kt contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
fun main() {
// Supplied input/output code: keep it as it is
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(", "))
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Classi e oggetti
Lavorare con i fileDefinire le classiCostruttori primariBlocchi init e convalidaCostruttori secondariRiepilogo - Tessera della biblioteca4Ereditarietà
Classi aperte e sottoclassiRidefinizione dei membrisuper e costruttoriClassi astratteRiepilogo - Elenco del personale2Proprietà e incapsulamento
Accessor personalizzatiModificatori di visibilitàSetter privatilazy e lateinitRipasso - Conto bancario5Interfacce
Dichiarare le interfacceMetodi predefinitiInterfacce multipleLe interfacce come tipiRiepilogo - Metodi di pagamento8Tipi generici
Funzioni genericheClassi genericheVincoli sui tipiVarianza con in e outRiepilogo - Coda con priorità11Progetto: Gestione della biblioteca
Libri e sociPrendere in prestito i libriEsercitati da solo: Playground Kotlin