Menu
Coddy logo textTech

전략 패턴

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

전략 패턴은 알고리즘의 각 변형을 공유 프로토콜 뒤에 고유한 타입으로 배치합니다. 이 패턴을 사용하는 코드는 전략을 보유하며 런타임에 전략을 교체할 수 있습니다:

protocol ShippingStrategy {
    func cost(weight: Int) -> Int
}
struct Standard: ShippingStrategy { func cost(weight: Int) -> Int { 5 + weight } }
struct Express: ShippingStrategy { func cost(weight: Int) -> Int { 15 + weight * 2 } }

struct Checkout {
    var shipping: any ShippingStrategy
    func total(price: Int, weight: Int) -> Int { price + shipping.cost(weight: weight) }
}

var c = Checkout(shipping: Standard())
print(c.total(price: 100, weight: 3))
c.shipping = Express()
print(c.total(price: 100, weight: 3))

출력:

108
121

Swift에서는 메서드가 하나인 전략에 클로저만으로 충분한 경우가 많습니다. 타입은 함수를 저장하고 호출합니다:

struct Sorter {
    var rule: (String, String) -> Bool
    func sort(_ words: [String]) -> [String] { words.sorted(by: rule) }
}

let words = ["banana", "kiwi", "apple"]
var s = Sorter(rule: <)
print(s.sort(words))
s.rule = { $0.count < $1.count }
print(s.sort(words))

출력:

["apple", "banana", "kiwi"]
["kiwi", "apple", "banana"]

전략은 알고리즘 내부의 switch를 대체합니다. 새로운 변형은 새로운 타입(또는 클로저)이 되며, 이를 사용하는 코드는 변경되지 않은 상태로 유지됩니다:

// 전략 없이: 새로운 옵션마다 이 함수를 수정함
func cost(kind: String, weight: Int) -> Int {
    switch kind { case "standard": return 5 + weight; default: return 15 + weight * 2 }
}
// 전략 사용 시: Checkout은 절대 변경되지 않음
struct Overnight: ShippingStrategy { func cost(weight: Int) -> Int { 40 } }

전략은 예를 들어 사용자 설정과 같은 데이터에서 작은 팩토리를 사용해 선택할 수 있습니다:

protocol Discount { func apply(_ price: Int) -> Int }
struct NoDiscount: Discount { func apply(_ p: Int) -> Int { p } }
struct Percent: Discount { let rate: Int; func apply(_ p: Int) -> Int { p - p * rate / 100 } }

func discount(for member: String) -> any Discount {
    member == "gold" ? Percent(rate: 20) : NoDiscount()
}

print(discount(for: "gold").apply(200))
print(discount(for: "basic").apply(200))

출력:

160
200
challenge icon

챌린지

쉬움

게임 캐릭터의 공격은 전략입니다. Attack 프로토콜에는 name과 damage(strength:) -> Int가 있습니다. Sword(strength * 2), Bow(strength + 5), 그리고 Magic(저장된 mana를 사용하며, mana가 10 이상이면 피해량은 strength * 3, 그렇지 않으면 1; damage 자체는 mana를 변경하지 않음)을 구현하세요. Hero는 자신의 strength와 attack을 저장하며, strike()는 Ada hits with sword for 20을 반환합니다.

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

여러분의 코드는 Attack.swift, Sword.swift, Bow.swift, Magic.swift 및 Hero.swift에 작성합니다. main.swift에는 제공된 입력/출력 코드가 포함되어 있으며 편집할 수 없습니다.

직접 해보기

// 제공된 입력/출력 코드: 그대로 유지하세요
var input: [String] = []
while let line = readLine() { input.append(line) }
let head = input[0].split(separator: ",").map(String.init)
var hero = Hero(name: head[0], strength: Int(head[1])!, attack: Sword())
for cmd in input.dropFirst() {
    let p = cmd.split(separator: " ").map(String.init)
    if p[0] == "strike" { print(hero.strike()); continue }
    switch p[1] {
    case "bow": hero.attack = Bow()
    case "magic": hero.attack = Magic(mana: Int(p[2])!)
    default: hero.attack = Sword()
    }
}
quiz icon실력 점검

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

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

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