johnhao
johnhao
发布于 2018-03-07 / 3 阅读
0

Swift-面向对象编程教程

1. 类与结构体

1.1 概念

  • 类(Class):引用类型,支持继承、类型转换、析构函数和引用计数

  • 结构体(Struct):值类型,不支持继承,适合表示简单的数据结构

1.2 原理

  • 引用类型:多个变量可以引用同一个实例,修改一个变量会影响其他引用该实例的变量

  • 值类型:每个变量都有自己的实例副本,修改一个变量不会影响其他变量

  • Swift中,数组、字典和字符串都是值类型,这与其他语言(如Java)不同

1.3 使用示例

1.3.1 类的定义与使用

// 定义类
class Person {
    // 存储属性
    var name: String
    var age: Int
// 计算属性
var isAdult: Bool {
    return age >= 18
}

// 初始化方法
init(name: String, age: Int) {
    self.name = name
    self.age = age
}

// 实例方法
func sayHello() {
    print("Hello, my name is \(name) and I'm \(age) years old.")
}

// 类型方法
static func createAdult(name: String) -> Person {
    return Person(name: name, age: 18)
}

}

// 使用类
let person1 = Person(name: "Alice", age: 25)
person1.sayHello() // 输出: Hello, my name is Alice and I’m 25 years old.
print(person1.isAdult) // 输出: true

let adult = Person.createAdult(name: "Bob")
adult.sayHello() // 输出: Hello, my name is Bob and I’m 18 years old.

// 引用类型特性
let person2 = person1
person2.name = "Alicia"
print(person1.name) // 输出: Alicia (因为person1和person2引用同一个实例)

1.3.2 结构体的定义与使用

// 定义结构体
struct Point {
    // 存储属性
    var x: Double
    var y: Double
// 计算属性
var distanceFromOrigin: Double {
    return sqrt(x * x + y * y)
}

// 初始化方法(结构体有默认的成员初始化器)
init(x: Double, y: Double) {
    self.x = x
    self.y = y
}

// 实例方法
mutating func moveBy(deltaX: Double, deltaY: Double) {
    x += deltaX
    y += deltaY
}

// 类型方法
static func origin() -> Point {
    return Point(x: 0, y: 0)
}

}

// 使用结构体
var point1 = Point(x: 3, y: 4)
print(point1.distanceFromOrigin) // 输出: 5.0

point1.moveBy(deltaX: 1, deltaY: 1)
print(point1.x, point1.y) // 输出: 4.0 5.0

let origin = Point.origin()
print(origin.x, origin.y) // 输出: 0.0 0.0

// 值类型特性
var point2 = point1
point2.x = 10
print(point1.x) // 输出: 4.0 (因为point1和point2是不同的副本)

1.3.3 类与结构体的区别

特性

结构体

类型

引用类型

值类型

继承

支持

不支持

类型转换

支持

不支持

析构函数

支持

不支持

引用计数

支持

不支持

成员初始化器

需手动实现

默认提供

适合场景

复杂对象,需要继承

简单数据结构,不需要继承

2. 继承与多态

2.1 概念

  • 继承(Inheritance):一个类可以继承另一个类的属性和方法

  • 父类(Superclass):被继承的类

  • 子类(Subclass):继承父类的类

  • 多态(Polymorphism):子类可以重写父类的方法,以提供不同的实现

2.2 原理

继承允许代码重用,子类可以继承父类的属性和方法,并可以添加自己的属性和方法或重写父类的方法。多态允许使用父类类型的变量来引用子类的实例,并在运行时调用正确的方法实现。

2.3 使用示例

2.3.1 类的继承

// 父类
class Vehicle {
    var speed: Double
    var numberOfWheels: Int
init(speed: Double, numberOfWheels: Int) {
    self.speed = speed
    self.numberOfWheels = numberOfWheels
}

func accelerate() {
    speed += 10
    print("Vehicle accelerating to \(speed) km/h")
}

func brake() {
    speed -= 10
    print("Vehicle braking to \(speed) km/h")
}

}

// 子类继承父类
class Car: Vehicle {
var numberOfDoors: Int

// 子类初始化方法
init(speed: Double, numberOfDoors: Int) {
    // 先初始化子类自己的属性
    self.numberOfDoors = numberOfDoors
    // 再调用父类的初始化方法
    super.init(speed: speed, numberOfWheels: 4)
}

// 重写父类方法
override func accelerate() {
    speed += 15
    print("Car accelerating to \(speed) km/h")
}

// 添加子类特有的方法
func honk() {
    print("Car honking: Beep! Beep!")
}

}

// 另一个子类
class Bicycle: Vehicle {
var hasBasket: Bool

init(speed: Double, hasBasket: Bool) {
    self.hasBasket = hasBasket
    super.init(speed: speed, numberOfWheels: 2)
}

override func accelerate() {
    speed += 5
    print("Bicycle accelerating to \(speed) km/h")
}

}

// 使用继承
let car = Car(speed: 0, numberOfDoors: 4)
car.accelerate() // 输出: Car accelerating to 15.0 km/h
car.honk() // 输出: Car honking: Beep! Beep!

let bicycle = Bicycle(speed: 0, hasBasket: true)
bicycle.accelerate() // 输出: Bicycle accelerating to 5.0 km/h

2.3.2 多态

// 多态:父类类型的数组可以存储不同子类的实例
let vehicles: [Vehicle] = [
    Car(speed: 0, numberOfDoors: 4),
    Bicycle(speed: 0, hasBasket: true),
    Car(speed: 0, numberOfDoors: 2)
]

// 遍历数组,调用accelerate方法,会根据实际类型调用正确的实现
for vehicle in vehicles {
vehicle.accelerate()
}
// 输出:
// Car accelerating to 15.0 km/h
// Bicycle accelerating to 5.0 km/h
// Car accelerating to 15.0 km/h

2.3.3 类型转换

// 类型检查
print(car is Vehicle) // 输出: true (car是Vehicle类型)
print(car is Car) // 输出: true (car是Car类型)
print(car is Bicycle) // 输出: false (car不是Bicycle类型)

// 向下类型转换(as? 和 as!)
for vehicle in vehicles {
if let car = vehicle as? Car {
car.honk() // 只有Car类型的实例才能调用honk方法
} else if let bicycle = vehicle as? Bicycle {
print("Bicycle has basket: (bicycle.hasBasket)")
}
}

3. 协议与扩展

3.1 协议

3.1.1 概念

  • 协议(Protocol):定义了一个蓝图,描述了类、结构体或枚举应该遵循的方法、属性和其他要求

  • 协议遵守:类、结构体或枚举可以遵守一个或多个协议,并实现协议中定义的要求

3.1.2 原理

协议提供了一种方式来定义通用的接口,实现了面向接口编程的思想。协议可以被多种类型遵守,从而实现多态和代码重用。

3.1.3 使用示例

// 定义协议
protocol Shape {
    // 协议属性要求
    var area: Double { get } // 只读属性
    var perimeter: Double { get } // 只读属性
// 协议方法要求
func draw()

// 协议初始化方法要求
init(width: Double, height: Double)

}

// 结构体遵守协议
struct Rectangle: Shape {
var width: Double
var height: Double

// 实现协议属性
var area: Double {
    return width * height
}

var perimeter: Double {
    return 2 * (width + height)
}

// 实现协议方法
func draw() {
    print("Drawing a rectangle with width \(width) and height \(height)")
}

// 实现协议初始化方法
init(width: Double, height: Double) {
    self.width = width
    self.height = height
}

}

// 类遵守协议
class Circle: Shape {
var radius: Double

// 计算属性,用于符合Shape协议的width和height要求
var width: Double {
    return 2 * radius
}

var height: Double {
    return 2 * radius
}

// 实现协议属性
var area: Double {
    return Double.pi * radius * radius
}

var perimeter: Double {
    return 2 * Double.pi * radius
}

// 实现协议方法
func draw() {
    print("Drawing a circle with radius \(radius)")
}

// 实现协议初始化方法
required init(width: Double, height: Double) {
    // 取width和height的平均值作为半径
    self.radius = (width + height) / 4
}

// 自定义初始化方法
init(radius: Double) {
    self.radius = radius
}

}

// 使用协议
let shapes: [Shape] = [
Rectangle(width: 10, height: 5),
Circle(radius: 7),
Rectangle(width: 3, height: 3)
]

for shape in shapes {
shape.draw()
print("Area: (shape.area)")
print("Perimeter: (shape.perimeter)")
print("—")
}

3.2 扩展

3.2.1 概念

  • 扩展(Extension):可以向现有类、结构体、枚举或协议添加新功能,无需修改原有的代码

  • 扩展可以添加计算属性、方法、初始化器、下标、嵌套类型和协议遵守

3.2.2 原理

扩展允许开发者在不修改原类型定义的情况下,为类型添加新功能。这对于扩展系统类型(如String、Array)或第三方库中的类型非常有用。

3.2.3 使用示例

3.2.3.1 扩展基本类型

// 扩展Int类型
extension Int {
    // 添加计算属性
    var isEven: Bool {
        return self % 2 == 0
    }
var isOdd: Bool {
    return self % 2 != 0
}

// 添加实例方法
func squared() -> Int {
    return self * self
}

// 添加下标
subscript(digitIndex: Int) -> Int {
    var decimalBase = 1
    for _ in 0..<digitIndex {
        decimalBase *= 10
    }
    return (self / decimalBase) % 10
}

}

// 使用扩展
let number = 42
print(number.isEven) // 输出: true
print(number.squared()) // 输出: 1764
print(number[0]) // 输出: 2 (个位)
print(number[1]) // 输出: 4 (十位)

3.2.3.2 扩展自定义类型

// 扩展之前定义的Person类
extension Person {
    // 添加新的初始化方法
    convenience init(name: String) {
        self.init(name: name, age: 0)
    }
// 添加新的实例方法
func introduce() -> String {
    return "Hi, I'm \(name), \(age) years old."
}

// 添加静态方法
static func createBaby(name: String) -> Person {
    return Person(name: name, age: 0)
}

}

// 使用扩展
let baby = Person(name: "Charlie")
print(baby.age) // 输出: 0
print(baby.introduce()) // 输出: Hi, I’m Charlie, 0 years old.

3.2.3.3 扩展协议

// 扩展Shape协议
extension Shape {
    // 为协议添加默认实现
    func describe() {
        print("This shape has an area of \(area) and a perimeter of \(perimeter)")
    }
// 添加新的要求
func isLarger(than other: Shape) -> Bool {
    return self.area > other.area
}

}

// 使用协议扩展
let rectangle = Rectangle(width: 5, height: 5)
let circle = Circle(radius: 3)

rectangle.describe() // 输出: This shape has an area of 25.0 and a perimeter of 20.0
circle.describe() // 输出: This shape has an area of 28.274333882308138 and a perimeter of 18.84955592153876

print(rectangle.isLarger(than: circle)) // 输出: false

3.3 泛型

3.3.1 概念

  • 泛型(Generic):允许编写灵活、可重用的函数和类型,这些函数和类型可以处理任何类型,而不需要指定具体类型

3.3.2 原理

泛型通过类型参数来实现,类型参数是一个占位符,在使用时被实际类型替换。泛型可以提高代码的重用性和类型安全性。

3.3.3 使用示例

3.3.3.1 泛型函数

// 定义泛型函数
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

// 使用泛型函数
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
print(someInt, anotherInt) // 输出: 107 3

var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
print(someString, anotherString) // 输出: world hello

3.3.3.2 泛型类型

// 定义泛型结构体
struct Stack<Element> {
    var items = [Element]()
// 入栈
mutating func push(_ item: Element) {
    items.append(item)
}

// 出栈
mutating func pop() -&gt; Element? {
    return items.popLast()
}

// 查看栈顶元素
func peek() -&gt; Element? {
    return items.last
}

// 检查栈是否为空
var isEmpty: Bool {
    return items.isEmpty
}

// 栈的大小
var count: Int {
    return items.count
}

}

// 使用泛型类型
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.push(3)
print(intStack.pop()) // 输出: Optional(3)

var stringStack = Stack<String>()
stringStack.push("one")
stringStack.push("two")
stringStack.push("three")
print(stringStack.peek()) // 输出: Optional("three")

4. 总结

Swift的面向对象编程特性包括类与结构体、继承与多态、协议与扩展以及泛型。这些特性共同构成了Swift强大的面向对象编程能力:

  • 类与结构体:类是引用类型,支持继承;结构体是值类型,适合表示简单的数据结构

  • 继承与多态:允许代码重用和灵活的设计,子类可以重写父类的方法,实现多态

  • 协议:定义了通用的接口,实现了面向接口编程的思想

  • 扩展:允许向现有类型添加新功能,无需修改原有的代码

  • 泛型:允许编写灵活、可重用的函数和类型,提高代码的重用性和类型安全性

掌握这些面向对象编程特性对于Swift开发至关重要,它们可以帮助你编写更加灵活、可重用和易于维护的代码。

5. 练习

  1. 创建一个Animal类,包含name属性和makeSound()方法,然后创建DogCat子类,重写makeSound()方法。

  2. 定义一个Playable协议,包含play()pause()方法,然后让MusicPlayer类和VideoPlayer类遵守这个协议。

  3. 创建一个泛型的Queue结构体,实现入队、出队、查看队首元素等功能。

  4. 扩展String类型,添加isPalindrome属性,用于判断字符串是否为回文。

  5. 创建一个Employee类,包含namesalary属性,然后创建Manager子类,添加teamSize属性,并实现一个计算属性totalTeamCost

通过这些练习,你可以巩固所学的Swift面向对象编程知识,提高自己的编程能力。