今天,您将学习一些真正的Swifty功能:协议和面向协议的编程(protocol-oriented programming —— POP)。
POP消除了大型复杂的继承层次结构,并用可以组合在一起的更小更简单的协议代替了它们。这确实是托尼·霍尔(Tony Hoare)多年前说过话的实现:“在每个大的程序中,都有一个小程序试图跳出来。(inside every large program, there is a small program trying to get out)”
您将使用第一个SwiftUI项目中的协议,它们将在您的整个Swift编码生涯中继续发挥着不可估量的作用——值得花时间来熟悉它们。
今天,您有6个一分钟的视频可供观看,并且您将了解协议,扩展以及两者的结合:协议扩展。观看完每个视频后,我们会进行一次简短的测试,以帮助您了解所教的内容。
1. 协议 Protocols – test
协议是描述某些事物必须具有的属性和方法的一种方式。然后,您可以告诉Swift哪些类型使用该协议,该过程称为采用或遵循协议。
例如,我们可以编写一个函数来接受具有id
属性的内容,但是我们并不在乎使用哪种类型的数据。我们将首先创建一个Identifiable
协议,该协议要求所有遵循协议的类型都具有一个可以读取(“get”)或写入(“set”)的id
字符串:
protocol Identifiable {
var id: String { get set }
}
我们无法创建该协议的实例——它是对所需内容的描述,而不是我们可以直接创建和使用的内容。但是我们可以创建一个遵循它的结构体:
struct User: Identifiable {
var id: String
}
最后,我们将编写一个displayID()
函数,该函数接受任何遵循Identifiable
协议的对象,比如上面的User
:
func displayID(thing: Identifiable) {
print("My ID is \(thing.id)")
}
2. 协议继承 Protocol inheritance – test
一个协议可以在称为协议继承的过程中从另一个协议继承。与类不同,在顶部添加自己的自定义项之前,您可以同时从多个协议继承。
我们将定义三个协议:Payable
需要采用的类型来实现calculateWages()
方法,NeedsTraining
需要采用的类型实现study()
方法,然后HasVacation
需要采用的类型来实现takeVacation()
方法:
protocol Payable {
func calculateWages() -> Int
}
protocol NeedsTraining {
func study()
}
protocol HasVacation {
func takeVacation(days: Int)
}
现在,我们可以创建一个Employee
协议,将它们集成到一个协议中。我们可以不需要在上面添加任何内容,因此我们只需要写大括号即可:
protocol Employee: Payable, NeedsTraining, HasVacation { }
现在,我们可以使新类型遵循该单一协议,而不是三个单独协议中的每一个。
3. 扩展 Extensions – test
扩展允许您将方法添加到现有类型中,以使它们执行原本没有设计要执行的操作。
例如,我们可以向Int
类型添加一个扩展,以便它具有一个squared()
方法,该方法返回当前数字乘以自身的值:
extension Int {
func squared() -> Int {
return self * self
}
}
要尝试该方法,只需创建一个整数,您将看到它现在具有squared()
方法:
let number = 8
number.squared()
Swift不允许您在扩展中添加存储属性,因此必须改用计算属性。例如,我们可以向整数添加一个新的isEven
计算属性,如果该属性包含偶数则返回true:
extension Int {
var isEven: Bool {
return self % 2 == 0
}
}
4. 协议扩展 Protocol extensions – test
协议可让您描述遵循协议的类或结构体需要有的方法,但不提供内部代码。扩展使您可以在方法内部提供代码,但仅影响一种数据类型——您不能同时将方法添加到许多类型中。
协议扩展同时解决了这两个问题:它们像常规扩展一样,只是扩展了整个协议,以便所有符合条件的类型都可以进行更改,而不是像Int
这样扩展特定类型。
例如,这是一个数组和一个包含一些名称的集合:
let pythons = ["Eric", "Graham", "John", "Michael", "Terry", "Terry"]
let beatles = Set(["John", "Paul", "George", "Ringo"])
Swift的数组和集合均符合称为Collection
的协议,因此我们可以对该协议编写一个扩展,以添加summary()
方法来整齐地打印集合:
extension Collection {
func summarize() {
print("There are \(count) of us:")
for name in self {
print(name)
}
}
}
Array
和Set
现在都将具有该方法,因此我们可以尝试一下:
pythons.summarize()
beatles.summarize()
5. 面向协议编程 Protocol-oriented programming – test
协议扩展可以为我们自己的协议方法提供默认实现。这使类型很容易符合协议,并允许使用一种称为“面向协议编程(POP)”的技术——围绕协议和协议扩展来编写代码。
首先,这是一个称为Identifiable
的协议,该协议要求任何符合条件的类型都具有id
属性和identify()
方法:
protocol Identifiable {
var id: String { get set }
func identify()
}
我们可以使每个采用此协议的类型都编写自己的identify()
方法,但是协议扩展允许我们提供默认值:
extension Identifiable {
func identify() {
print("My ID is \(id).")
}
}
现在,当我们创建一个符合Identifiable
的类型时,它将自动获得identify()
:
struct User: Identifiable {
var id: String
}
let twostraws = User(id: "twostraws")
twostraws.identify()
6. 协议和扩展:总结 Protocols and extensions summary – test
您已经完成了本系列第九部分,所以让我们总结一下:
1、协议描述了采用的类型必须具有的方法和属性,但未提供这些方法的实现。
2、您可以在其他协议的基础之上构建协议,类似于类。
3、扩展使您可以向特定类型(例如Int
)添加方法和计算属性。
4、协议扩展使您可以向协议添加方法和计算属性。
5、面向协议编程是一种将应用程序体系结构设计为一系列协议,然后使用协议扩展来提供默认方法实现的实践。
赏我一个赞吧~~~