Menu
Coddy logo textTech

전략 패턴

Coddy Kotlin 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 45번째.

전략 패턴은 알고리즘의 각 변형을 공유 인터페이스 뒤에 별도의 클래스로 배치합니다. 이를 사용하는 코드는 하나의 전략을 보유하며 프로그램 실행 중에 이를 교체할 수 있습니다:

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)
}

main 내부:

val checkout = Checkout(Standard())
println(checkout.total(100, 3))
checkout.shipping = Express()
println(checkout.total(100, 3))

출력:

108
121

전략에 단일 메서드만 있다면 함수 타입으로 충분합니다. 클래스는 함수를 저장하고 호출합니다:

class Formatter(var style: (String) -> String) {
    fun show(words: List<String>) = words.joinToString(" ") { style(it) }
}

main 내부:

val f = Formatter { it.uppercase() }
println(f.show(listOf("hello", "world")))
f.style = { it.reversed() }
println(f.show(listOf("hello", "world")))

출력:

HELLO WORLD
olleh dlrow

전략은 알고리즘 내부의 when을 대체합니다. when을 사용하면 새로운 옵션이 추가될 때마다 알고리즘을 편집해야 합니다. 전략을 사용하면 새로운 옵션은 새로운 클래스나 람다가 되며, Checkout은 절대 변경되지 않습니다.

// 전략 없이: 모든 새로운 옵션이 이 함수를 수정함
fun cost(kind: String, kg: Int) = when (kind) {
    "standard" -> 5 + kg
    else -> 15 + kg * 2
}
// 전략 사용 시: 클래스를 추가하고 Checkout은 그대로 둠
class Overnight : Shipping {
    override fun cost(kg: Int) = 40
}

전략은 고객의 요금제와 같은 데이터에서 맵이나 작은 팩토리를 사용해 선택하는 경우가 많습니다.

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

main 내부에서:

println(finalPrice("gold", 200))
println(finalPrice("silver", 200))
println(finalPrice("basic", 200))

출력:

160
180
200
challenge icon

챌린지

쉬움

영웅의 공격은 전략입니다. name과 damage(strength)를 포함하는 Attack 인터페이스가 제공됩니다. Sword(strength의 2배만큼 피해), Bow(strength에 5를 더한 값) 및 Magic(mana)(mana가 10 이상이면 strength의 3배, 그렇지 않으면 1)를 작성하세요. Hero(name, strength, attack)는 언제든지 자신의 attack을 변경할 수 있으며, 어떤 공격을 사용하는지 확인하지 않고 Ada hits with sword for 20을 반환하는 strike()를 가집니다.

제공된 코드는 name,strength를 읽은 다음 equip bow, equip magic 15, equip sword 또는 strike 명령을 읽고, 각 공격의 결과를 출력합니다.

코드는 Sword.kt, Bow.kt, Magic.kt, Hero.kt 및 Attack.kt에 작성하세요. Main.kt에는 제공된 입력/출력 코드가 들어 있으며 편집할 수 없습니다.

직접 해보기

fun main() {
    // 제공된 입력/출력 코드: 그대로 유지하세요
    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()
        }
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: Kotlin 플레이그라운드