当苹果公司在2015年的全球开发者大会(WWDC)上宣布发布第一种面向协议的语言--Swift时,这表明他们将从现有的面向对象的编程--Objective-C中转移出来。
但由于Objective-C利用隐性共享继承,创建新的对象成为一个缓慢的过程,而且新的对象往往具有不需要的功能。在这种情况下,如果一个类的层次结构很复杂,维护它就会造成效率低下和竞赛条件等问题。
有了Swift的协议范式,开发者现在可以在不继承的情况下构建对象,对象可以被现有的代码使用,而且一个类可以在多个协议下工作,不需要继承。
在这篇文章中,我们将讨论Swift的协议范式及其优势。面向对象编程的知识对理解本帖的内容有帮助。
什么是协议,它们在Swift中是如何工作的?
一般来说,一个协议。
- 是一个类或结构所遵循的蓝图
- 是一个供无关对象依赖的通信合同
- 定义了方法和值
为了理解协议在 Swift 中如何工作,让我们假设我们正在构建应用软件,并且必须对需求进行建模以满足应用。我们可以从一个超类开始,通过继承来塑造关系,或者从一个协议开始,通过实现来塑造关系。
如果我们想为我们的应用程序建立一个工资汇款系统,并且我们有一个Employee 类,使用协议看起来像下面这样。
protocol EmployeeProtocol {
var emplname: String { get }
var description: String { get }
var salary: Int { get set }
func paySalary(salary: Int) -> String
}
通常,如果我们使用get ,我们可以把它变成一个const 、var 、let 、或计算的属性。然而,为salary 属性使用属性声明get set ,会限制var salary: Int { get set } 到var 。
如果我们想写一个遵循这个协议的类,比如说Employee 类,我们就有以下情况。
class Employee: EmployeeProtocol {
var emplname: String = "Victor Jonah"
var description: String = "Software Engineer"
var salary: Int = 5000
func paySalary(salary: Int) -> String {
return "Salary disbursed to {emplname}"
}
}
综上所述,协议允许我们对我们的方法、属性和函数进行分组。然而,这些协议只能符合类、枚举和结构。
多个协议可以符合一个对象,但它们必须用逗号隔开。
struct Player: MainPlayer, EnemyPlayer {
// code definition
}
另外,如果一个类有一个超类,我们可以在超类名称后面定义任何协议。
class TheClass: ItsSuperclass, FirstProtocol, SecondProtocol {
// class definition goes here
}
我们可以在计算属性的协议中使用enum ,但它们对存储属性不起作用。
enum Employer: EmployerProtocol {
var name: String {
return "Alex"
}
var description: String {
return "CEO"
}
var salary: Int {
get {
return
}
}
}
如果协议不符合类、结构或枚举,Swift还会在编译时抛出一个错误。
一个Swift移动协议的例子
让我们通过一个移动实例来看看协议的一个更常见的使用情况。
protocol Mobile {
var name: String { get }
var iEMICode: Int { get }
var sIMCard: String { get }
var processor: String { get }
var internalMemory: Int { get}
var isSingleSIM: Bool { get }
mutating func GetIEMICode() -> String
func SendMessage() -> String
func Dial() -> String
func Receive() -> String
init(name: String)
}
struct Apple: Mobile {
var name: String = "Apple"
init(name: String) {
self.name = name
}
var iEMICode: Int = 3244332
var sIMCard: String = "Vodaphone"
var processor: String = "Snapdragon"
var internalMemory: Int = 213424
var isSingleSIM: Bool = true
mutating func GetIEMICode() -> String {
return "IEMEICode"
}
func SendMessage() -> String {
return "Message sent"
}
func Dial() -> String {
return "Dialed"
}
func Receive() -> String {
return "Receiving call"
}
}
struct Samsung: Mobile {
var name: String = "Samsung"
init(name: String) {
self.name = name
}
var iEMICode: Int = 3243433
var sIMCard: String = "TMobile"
var processor: String = "Snapdragon"
var internalMemory: Int = 324432
var isSingleSIM: Bool = false
func GetIEMICode() -> String {
return "IEMEICode"
}
func SendMessage() -> String {
return "Message sent"
}
func Dial() -> String {
return "Dialed"
}
func Receive() -> String {
return "Receiving call"
}
}
请注意,当我们有一个对象必须改变它的一个属性时,第9行的mutating 关键字就会发挥作用。我们必须在协议中指定GetIEMICode() 是一个变异方法。在我们的结构中,我们也必须指定关键字mutating ,但不是在类中。
Swift中协议的优势
从上面的例子中,我们可以看到为什么协议是有用的,以及为什么Swift使用面向协议的范式。使用协议的优势体现在以下几个方面。
代码的清晰性
命名协议可以让人更好地理解其实例。在我们的第一个例子中,我们创建了一个符合Employee 类的EmployeeProtocol ,显示了协议如何为类、枚举或结构提供意义。
正如Dave Abrahams在2015年WWDC上所说,"不要从一个类开始,要从一个协议开始。"
可重用性
通过协议扩展,我们可以在它们符合的类、枚举或结构中为我们的方法提供一个默认实现。我们可以在下面的代码中看到这一点。
protocol Person {
var name: String { get }
var age: Int { get }
var gender: String { get }
func speak()
}
extension Person {
func speak() {
print("Hello, this works!")
}
}
class Male: Person {
var name: String = ""
var age: Int = 23
var gender: String = "Male"
}
struct Female: Person {
var name: String
var age: Int
var gender: String
}
通过在第9行使用extension 关键字创建一个默认功能,我们不需要在我们的类或结构中重复它。
类的分离
协议还消除了类、枚举和结构之间相互依赖的需要,因为它们不使用继承。
结论
综上所述,Swift中的协议提供了不相关对象之间的通信,我们在其中定义了类、枚举和结构中观察到的方法和变量。因为Swift接受了面向协议的范式,我们可以在定义类、结构或枚举之前对我们的系统进行建模,使这个过程更加高效。
The postUnderstanding protocols in Swiftappeared first onLogRocket Blog.