Patron Strategy
Fait partie de la section Programmation orientée objet du Journey Kotlin de Coddy. Leçon 45 sur 57.
Le modèle de stratégie place chaque variante d’un algorithme dans sa propre classe, derrière une interface commune. Le code qui l’utilise conserve une stratégie et peut la remplacer pendant l’exécution du programme :
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)
}Dans main :
val checkout = Checkout(Standard())
println(checkout.total(100, 3))
checkout.shipping = Express()
println(checkout.total(100, 3))Sortie :
108
121Lorsqu’une stratégie ne comporte qu’une seule méthode, un type fonction suffit. La classe stocke une fonction et l’appelle :
class Formatter(var style: (String) -> String) {
fun show(words: List<String>) = words.joinToString(" ") { style(it) }
}Dans main :
val f = Formatter { it.uppercase() }
println(f.show(listOf("hello", "world")))
f.style = { it.reversed() }
println(f.show(listOf("hello", "world")))Sortie :
HELLO WORLD
olleh dlrowUne stratégie remplace un when à l’intérieur de l’algorithme. Avec le when, chaque nouvelle option implique de modifier l’algorithme. Avec les stratégies, une nouvelle option correspond à une nouvelle classe ou lambda, et Checkout ne change jamais :
// sans stratégie : chaque nouvelle option modifie cette fonction
fun cost(kind: String, kg: Int) = when (kind) {
"standard" -> 5 + kg
else -> 15 + kg * 2
}
// avec une stratégie : ajoutez une classe, laissez Checkout tranquille
class Overnight : Shipping {
override fun cost(kg: Int) = 40
}Une stratégie est souvent choisie à partir de données, telles que le forfait d’un client, avec une map ou une petite fabrique :
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) ?: priceÀ l’intérieur de main :
println(finalPrice("gold", 200))
println(finalPrice("silver", 200))
println(finalPrice("basic", 200))Sortie :
160
180
200Défi
FacileL’attaque d’un héros est une stratégie. L’interface Attack (avec name et damage(strength)) est fournie. Écrivez Sword (dégâts égaux à la force multipliée par 2), Bow (force plus 5) et Magic(mana) (force multipliée par 3 lorsque le mana est supérieur ou égal à 10, sinon 1). Hero(name, strength, attack) peut modifier son attack à tout moment, et strike() renvoie Ada hits with sword for 20 sans vérifier quelle attaque il possède.
Le code fourni lit name,strength, puis les commandes equip bow, equip magic 15, equip sword ou strike, et affiche le résultat de chaque attaque.
Votre code doit être placé dans Sword.kt, Bow.kt, Magic.kt, Hero.kt et Attack.kt. Main.kt contient le code fourni pour les entrées et les sorties et ne peut pas être modifié.
Essayez vous-même
fun main() {
// Code d'entrée/sortie fourni : le garder tel quel
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()
}
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Classes et objets
Travailler avec des fichiersDéfinir des classesConstructeurs primairesBlocs init et validationConstructeurs secondairesRécapitulatif - Carte de bibliothèque4Héritage
Classes ouvertes et sous-classesRedéfinition des membressuper et constructeursClasses abstraitesRécapitulatif – Annuaire du personnel2Propriétés et encapsulation
Accesseurs personnalisésModificateurs de visibilitéSetters privéslazy et lateinitRécapitulatif - Compte bancaire5Interfaces
Déclarer des interfacesMéthodes par défautInterfaces multiplesInterfaces en tant que typesRécapitulatif - Méthodes de paiement8Génériques
Fonctions génériquesClasses génériquesContraintes de typeVariance avec in et outRécapitulatif - File de priorité11Projet : Gestion de bibliothèque
Livres et membresEmprunter des livresEntraînez-vous par vous-même : Playground Kotlin