Padrão Strategy
Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 45 de 57.
O padrão strategy coloca cada variante de um algoritmo em sua própria classe, por trás de uma interface compartilhada. O código que o utiliza mantém uma estratégia e pode substituí-la enquanto o programa é executado:
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)
}Dentro de main:
val checkout = Checkout(Standard())
println(checkout.total(100, 3))
checkout.shipping = Express()
println(checkout.total(100, 3))Saída:
108
121Quando uma estratégia tem um único método, um tipo de função é suficiente. A classe armazena uma função e a chama:
class Formatter(var style: (String) -> String) {
fun show(words: List<String>) = words.joinToString(" ") { style(it) }
}Dentro de main:
val f = Formatter { it.uppercase() }
println(f.show(listOf("hello", "world")))
f.style = { it.reversed() }
println(f.show(listOf("hello", "world")))Saída:
HELLO WORLD
olleh dlrowUma estratégia substitui um when dentro do algoritmo. Com o when, cada nova opção significa editar o algoritmo. Com estratégias, uma nova opção é uma nova classe ou lambda, e Checkout nunca muda:
// sem uma estratégia: cada nova opção edita esta função
fun cost(kind: String, kg: Int) = when (kind) {
"standard" -> 5 + kg
else -> 15 + kg * 2
}
// com uma estratégia: adicione uma classe, deixe o Checkout sozinho
class Overnight : Shipping {
override fun cost(kg: Int) = 40
}Uma estratégia geralmente é escolhida a partir de dados, como o plano de um cliente, com um mapa ou uma pequena fábrica:
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) ?: priceDentro de main:
println(finalPrice("gold", 200))
println(finalPrice("silver", 200))
println(finalPrice("basic", 200))Saída:
160
180
200Desafio
FácilO ataque de um herói é uma estratégia. A interface Attack (com name e damage(strength)) é fornecida. Escreva Sword (dano igual à força multiplicada por 2), Bow (força mais 5) e Magic(mana) (força multiplicada por 3 quando a mana é de pelo menos 10; caso contrário, 1). Hero(name, strength, attack) pode alterar seu attack a qualquer momento, e strike() retorna Ada hits with sword for 20 sem verificar qual ataque ele possui.
O código fornecido lê name,strength e, em seguida, os comandos equip bow, equip magic 15, equip sword ou strike, e imprime o resultado de cada ataque.
Seu código deve ser inserido em Sword.kt, Bow.kt, Magic.kt, Hero.kt e Attack.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
fun main() {
// Código de entrada/saída fornecido: mantenha-o como está
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()
}
}
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesConstrutores PrimáriosBlocos init e ValidaçãoConstrutores SecundáriosRecapitulação - Cartão da Biblioteca4Herança
Classes Abertas e SubclassesSobrescrevendo Membrossuper e ConstrutoresClasses AbstratasRevisão - Diretório de Funcionários2Propriedades e Encapsulamento
Acessores PersonalizadosModificadores de VisibilidadeSetters Privadoslazy e lateinitRevisão - Conta Bancária5Interfaces
Declarando InterfacesMétodos PadrãoMúltiplas InterfacesInterfaces como TiposRecapitulação - Métodos de Pagamento8Genéricos
Funções genéricasClasses genéricasRestrições de tipoVariância com in e outRecapitulação - Fila de prioridade11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Playground de Kotlin