Wzorzec strategii
Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 45 z 57.
Wzorzec strategii umieszcza każdy wariant algorytmu we własnej klasie, która implementuje wspólny interfejs. Kod, który z niego korzysta, przechowuje jedną strategię i może ją zmienić podczas działania programu:
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)
}Wewnątrz main:
val checkout = Checkout(Standard())
println(checkout.total(100, 3))
checkout.shipping = Express()
println(checkout.total(100, 3))Wynik:
108
121Gdy strategia ma jedną metodę, wystarczy typ funkcji. Klasa przechowuje funkcję i ją wywołuje:
class Formatter(var style: (String) -> String) {
fun show(words: List<String>) = words.joinToString(" ") { style(it) }
}Wewnątrz main:
val f = Formatter { it.uppercase() }
println(f.show(listOf("hello", "world")))
f.style = { it.reversed() }
println(f.show(listOf("hello", "world")))Wynik:
HELLO WORLD
olleh dlrowStrategia zastępuje when wewnątrz algorytmu. W przypadku when każda nowa opcja oznacza edycję algorytmu. W przypadku strategii nowa opcja to nowa klasa lub lambda, a Checkout nigdy się nie zmienia:
// bez strategii: każda nowa opcja wymaga zmiany tej funkcji
fun cost(kind: String, kg: Int) = when (kind) {
"standard" -> 5 + kg
else -> 15 + kg * 2
}
// ze strategią: dodaj klasę, nie zmieniaj Checkout
class Overnight : Shipping {
override fun cost(kg: Int) = 40
}Strategia jest często wybierana na podstawie danych, takich jak plan klienta, za pomocą mapy lub małej fabryki:
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) ?: priceWewnątrz main:
println(finalPrice("gold", 200))
println(finalPrice("silver", 200))
println(finalPrice("basic", 200))Wynik:
160
180
200Wyzwanie
ŁatwyAtak bohatera to strategia. Interfejs Attack (z elementami name i damage(strength)) jest dostarczony. Napisz Sword (obrażenia równe sile pomnożonej przez 2), Bow (siła plus 5) oraz Magic(mana) (siła pomnożona przez 3, gdy mana wynosi co najmniej 10, w przeciwnym razie 1). Hero(name, strength, attack) może w dowolnym momencie zmienić swoje attack, a strike() zwraca Ada hits with sword for 20, nie sprawdzając, którego ataku używa.
Dostarczony kod odczytuje name,strength, a następnie polecenia equip bow, equip magic 15, equip sword lub strike i wypisuje wynik każdego ataku.
Twój kod umieść w plikach Sword.kt, Bow.kt, Magic.kt, Hero.kt i Attack.kt. Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
fun main() {
// Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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()
}
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Klasy i obiekty
Praca z plikamiDefiniowanie klasKonstruktory główneBloki init i walidacjaKonstruktory dodatkowePodsumowanie — karta biblioteczna4Dziedziczenie
Klasy otwarte i podklasyNadpisywanie składowychsuper i konstruktoryKlasy abstrakcyjnePodsumowanie – katalog pracowników7Klasy specjalne
Klasy danychKlasy wyliczenioweHierarchie zapieczętowaneequals, hashCode, toStringPodsumowanie — śledzenie zamówień10Wzorce projektowe, część 2
Delegowanie za pomocą byWzorzec dekoratoraWzorzec budowniczegoWzorzec stanu2Właściwości i hermetyzacja
Własne akcesoryModyfikatory widocznościPrywatne setterylazy i lateinitPowtórka – konto bankowe5Interfejsy
Deklarowanie interfejsówMetody domyślneWiele interfejsówInterfejsy jako typyPowtórzenie – metody płatności8Typy generyczne
Funkcje generyczneKlasy generyczneOgraniczenia typówKowariancja i kontrawariancja: in i outPodsumowanie — kolejka priorytetowa11Projekt: Zarządzanie biblioteką
Książki i czytelnicyWypożyczanie książekPoćwicz samodzielnie: Edytor online Kotlin