Menu
Coddy logo textTech

final과 계층 구조

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

final은 더 이상의 오버라이드를 막습니다. final func는 어떤 서브클래스에서도 오버라이드할 수 없으며, final class는 아예 서브클래스로 만들 수 없습니다:

class Account {
    final func id() -> String { "ACC" }   // 오버라이드할 수 없음
}

final class Receipt { }                  // 서브클래스로 만들 수 없음
// class GiftReceipt: Receipt { }        // 오류: final 클래스로부터의 상속

서브클래스에서 변경해서는 안 되는 메서드(예: 규칙을 적용하는 메서드)에는 final을 표시합니다. 다른 메서드는 세부 사항을 사용자 지정할 수 있도록 여전히 재정의할 수 있습니다:

class Checkout {
    final func total(_ prices: [Int]) -> Int {
        let sum = prices.reduce(0, +)
        return sum - discount(sum)
    }
    func discount(_ sum: Int) -> Int { 0 }
}

class SaleCheckout: Checkout {
    override func discount(_ sum: Int) -> Int { sum / 10 }
}

print(Checkout().total([50, 50]))
print(SaleCheckout().total([50, 50]))

출력:

100
90

계층 구조는 여러 수준을 가질 수 있습니다. 메서드는 객체 자체의 클래스에서 시작해 상위 클래스로 거슬러 올라가며 검색되고, 가장 먼저 발견된 구현이 실행됩니다:

class Animal {
    func move() -> String { "moves" }
    func eat() -> String { "eats" }
}
class Bird: Animal {
    override func move() -> String { "flies" }
}
class Penguin: Bird {
    override func move() -> String { "swims" }
}

let p = Penguin()
print(p.move())
print(p.eat())

출력:

swims
eats

계층 구조를 얕게 유지하세요. 한 객체의 동작이 여러 클래스에 걸쳐 분산되기 때문에 깊은 연결은 따라가기 어렵습니다. 타입들이 is-a 관계 없이 동작을 공유할 때는 프로토콜(다음 장)이 일반적으로 더 나은 도구입니다.

// 깊고 취약한
class A { }
class B: A { }
class C: B { }
class D: C { }      // D는 무엇을 상속하며, 어디서부터인가?
challenge icon

챌린지

쉬움

Discount에는 가격에서 amount(for:)를 뺀 값을 반환하되 0보다 작아지지 않도록 하는 final 메서드 apply(to:)가 있으며, amount(for:)는 0을 반환합니다. PercentOff(저장된 percent, amount = price 곱하기 percent / 100)와 FixedOff(저장된 value, amount = value)를 선언하고, 각각 이니셜라이저와 amount(for:)의 재정의를 구현하세요. apply(to:) 자체는 Discount에 그대로 둡니다.

제공된 코드는 가격을 읽은 다음 p,10 또는 f,300을 할인하고, 각 할인을 가격에 적용한 후 1000 -> 900을 출력합니다.

코드는 Discount.swift, PercentOff.swift 및 FixedOff.swift에 작성합니다. main.swift에는 제공된 입력/출력 코드가 있으며 편집할 수 없습니다.

직접 해보기

// 제공된 입출력 코드: 그대로 유지하세요
var input: [String] = []
while let line = readLine() { input.append(line) }
let price = Int(input[0])!
for line in input.dropFirst() {
    let p = line.split(separator: ",").map(String.init)
    let d: Discount = p[0] == "p" ? PercentOff(percent: Int(p[1])!) : FixedOff(value: Int(p[1])!)
    print("\(price) -> \(d.apply(to: price))")
}
quiz icon실력 점검

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

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

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