Menu
CoddyTech

多态

本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 32 课,共 57 课。

多态是指同一段代码可以处理多种类型的值,并且每个值都以自己的方式响应。下面的循环会调用 sound(),而无需知道其中包含的是哪种动物:

class Animal {
    func sound() -> String { "..." }
}
class Dog: Animal {
    override func sound() -> String { "Woof" }
}
class Cow: Animal {
    override func sound() -> String { "Moo" }
}

let farm: [Animal] = [Dog(), Cow(), Dog()]
for a in farm { print(a.sound()) }

输出:

Woof
Moo
Woof

Swift 会在运行时根据实际对象决定运行哪个实现。变量的声明类型并不重要,重要的是对象的类型:

class Animal {
    func sound() -> String { "..." }
}
class Cat: Animal {
    override func sound() -> String { "Meow" }
}

let pet: Animal = Cat()
print(pet.sound())

输出:

Meow

协议为结构体和枚举提供了同样的灵活性。这里有一个函数,可以打印任意由 Drawable 值组成的列表:

protocol Drawable {
    func draw() -> String
}
struct Line: Drawable {
    let length: Int
    func draw() -> String { String(repeating: "-", count: length) }
}
struct Box: Drawable {
    func draw() -> String { "[ ]" }
}

func render(_ items: [any Drawable]) -> String {
    items.map { $0.draw() }.joined(separator: " ")
}

print(render([Line(length: 3), Box(), Line(length: 1)]))

输出:

--- [ ] -

多态可以替代针对不同类型事物的冗长 if/switch 链。你不必先询问一个值是什么,再决定要做什么,而是让这个值去完成相应的操作。添加一种新类型时,只需添加一个新类型,而不必修改每个 switch:

// 不使用多态
if kind == "dog" { print("Woof") } else if kind == "cow" { print("Moo") }

// 使用多态
for animal in farm { print(animal.sound()) }
challenge icon

挑战

简单

Animal 有 name、legs()(4)和 describe(),后者会返回由 legs() 和 sound() 构成的 Rex has 4 legs and says Woof。通过只重写 legs() 和 sound(),声明 Dog(声音为 Woof)、Bird(2 条腿,声音为 Tweet)和 Snake(0 条腿,声音为 Hiss)。

提供的代码会读取 dog,Rex、bird,Pip 或 snake,Kaa 这样的行,将动物存储在一个 [Animal] 数组中,并为每只动物打印 describe() 的结果。

你的代码应写在 Animal.swift、Dog.swift、Bird.swift 和 Snake.swift 中。main.swift 存放提供的输入/输出代码,不能编辑。

亲手试试

// 提供的输入/输出代码:保持原样
var input: [String] = []
while let line = readLine() { input.append(line) }
var zoo: [Animal] = []
for line in input {
    let p = line.split(separator: ",").map(String.init)
    switch p[0] {
    case "dog": zoo.append(Dog(name: p[1]))
    case "bird": zoo.append(Bird(name: p[1]))
    default: zoo.append(Snake(name: p[1]))
    }
}
for a in zoo { print(a.describe()) }
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Swift 在线编辑器