final 与继承层次结构
本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 25 课,共 57 课。
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 继承了什么?从哪里继承的?挑战
简单Discount 有一个 final 方法 apply(to:),它返回价格减去 amount(for:) 后的结果,但不会低于 0;amount(for:) 返回 0。声明 PercentOff(存储 percent,金额 = 价格乘以百分比再除以 100)和 FixedOff(存储 value,金额 = 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))")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Swift 在线编辑器