Pattern Strategy
Fa parte della sezione Programmazione orientata agli oggetti del percorso Kotlin di Coddy. Lezione 45 di 57.
Il pattern strategy inserisce ogni variante di un algoritmo in una propria classe dietro un'interfaccia condivisa. Il codice che lo usa contiene una strategia e può sostituirla mentre il programma è in esecuzione:
interface Shipping {
fun cost(kg: Int): Int
}
class Standard : Shipping {
override fun cost(kg: Int) = 5 + kg
}
class Express : Shipping {
override fun cost(kg: Int) = 15 + kg * 2
}
class Checkout(var shipping: Shipping) {
fun total(price: Int, kg: Int) = price + shipping.cost(kg)
}All'interno di main:
val checkout = Checkout(Standard())
println(checkout.total(100, 3))
checkout.shipping = Express()
println(checkout.total(100, 3))Output:
108
121Quando una strategia ha un solo metodo, è sufficiente un tipo funzione. La classe memorizza una funzione e la richiama:
class Formatter(var style: (String) -> String) {
fun show(words: List<String>) = words.joinToString(" ") { style(it) }
}All'interno di main:
val f = Formatter { it.uppercase() }
println(f.show(listOf("hello", "world")))
f.style = { it.reversed() }
println(f.show(listOf("hello", "world")))Output:
HELLO WORLD
olleh dlrowUna strategia sostituisce un when all'interno dell'algoritmo. Con when, ogni nuova opzione implica modificare l'algoritmo. Con le strategie, una nuova opzione è una nuova classe o lambda, e Checkout non cambia mai:
// senza una strategia: ogni nuova opzione richiede di modificare questa funzione
fun cost(kind: String, kg: Int) = when (kind) {
"standard" -> 5 + kg
else -> 15 + kg * 2
}
// con una strategia: aggiungi una classe, lascia Checkout invariato
class Overnight : Shipping {
override fun cost(kg: Int) = 40
}Una strategia viene spesso scelta in base ai dati, come il piano di un cliente, usando una mappa o una piccola fabbrica:
val discounts: Map<String, (Int) -> Int> = mapOf(
"gold" to { price -> price * 80 / 100 },
"silver" to { price -> price * 90 / 100 }
)
fun finalPrice(plan: String, price: Int) = discounts[plan]?.invoke(price) ?: priceAll'interno di main:
println(finalPrice("gold", 200))
println(finalPrice("silver", 200))
println(finalPrice("basic", 200))Output:
160
180
200Sfida
FacileL’attacco di un eroe è una strategia. L’interfaccia Attack (con name e damage(strength)) è fornita. Scrivi Sword (danno pari alla forza moltiplicata per 2), Bow (forza più 5) e Magic(mana) (forza moltiplicata per 3 quando il mana è almeno 10, altrimenti 1). Hero(name, strength, attack) può cambiare il proprio attack in qualsiasi momento, e strike() restituisce Ada hits with sword for 20 senza controllare quale attacco abbia.
Il codice fornito legge name,strength e poi i comandi equip bow, equip magic 15, equip sword oppure strike, e stampa il risultato di ogni colpo.
Il tuo codice va in Sword.kt, Bow.kt, Magic.kt, Hero.kt e Attack.kt. Main.kt contiene il codice fornito per l’input/output e non può essere modificato.
Provalo tu
fun main() {
// Codice di input/output fornito: lascialo così com'è
val input = generateSequence(::readLine).toList()
val (name, strength) = input[0].split(",")
val hero = Hero(name, strength.toInt(), Sword())
for (cmd in input.drop(1)) {
val p = cmd.split(" ")
if (p[0] == "strike") {
println(hero.strike())
continue
}
hero.attack = when (p[1]) {
"bow" -> Bow()
"magic" -> Magic(p[2].toInt())
else -> Sword()
}
}
}
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