书籍链接:《Pro Swift》 (链接需要梯子才能打得开)。
一、面向协议编程 (protocol-oriented programming(POP))
Swift给我们带来了一种新的设计模式,面向协议编程(后面用POP表示)。他继承了面向对象(后面用OOP表示)的封装和多肽特性,但是没有继承特性。POP让我们以横向的方式构建应用,而不是纵向:通过实现协议来添加方法或者属性,而不是通过继承。
二、协议扩展细节
1. 为协议方法提供默认的实现
在创建了一个协议之后,如果我们想给协议的某个方法提供默认的实现,可以用扩展来实现:
protocol Payable {
func calculateWages() -> Int
}
extension Payable {
func calculateWages() -> Int {
return 10000
}
}
2. Objective-C无法访问协议的默认实现
例如,刚刚那个例子,我们在协议加上@objc,让Objective-C上可以访问到Payable协议:
@objc protocol Payable {
func calculateWages() -> Int
}
extension Payable {
func calculateWages() -> Int {
return 10000
}
}
虽然我们用扩展为calculateWages()提供了默认实现,但是这个实现在Objective-C中是访问不到的,Objective-C必须自己实现这个方法。
3. 一个容易出现的错误
我们先看代码:
我们把协议里面的calculateWages()注释掉,然后扩展Payable实现了calculateWages()方法;定义了Surgeon并用遵循Payable协议,用扩展重写Pauyable的calculateWages()方法;最后创建了两个实例gregory和doogie。结果是gregory.calculateWages()返回20000,而doogie.calculateWages()返回10000。
即使gregory和doogie都是Surgeon的实例,但是doogie是以Payable的类型存储的。因为我们在payable协议的创建里把calculateWages()注释掉了,所以Swift在调用calculateWages()的时候是以他们存储的类型为准的,gregory的存储类型是Sugreon,所以调用Sugreon的方法,返回20000;而doogie是以Payable的类型存储的,所以调用Payable的方法,返回10000。
如果我们恢复payable协议的calculateWages(),他们的结果都返回20000。
三、横向思考
文章开始我们提到POP让我们以横向的方式构建应用,而不是纵向。纵向就意味着继承,先有一个基类,然后再不断地创建子类;而横向则是通过创建协议,然后通过实现协议的规定,添加特定的方法。我们可以实现多个协议,这听起来就像多继承。
四、POP练习
首先我们先定义六个协议,每个协议有一个方法,并且都提供了默认的实现:
protocol Payable {
func calculateWages() -> Int
}
extension Payable {
func calculateWages() -> Int {
return 10000
}
}
// 提供治疗
protocol ProvidesTreatment {
func treat(name: String)
}
extension ProvidesTreatment {
func treat(name: String) {
print("I have treated \(name)")
}
}
// 提供诊断
protocol ProvidesDiagnosis {
func diagnose() -> String
}
extension ProvidesDiagnosis {
func diagnose() -> String {
return "He's dead, Jim"
}
}
// 进行手术
protocol ConductsSurgery {
func performSurgery()
}
extension ConductsSurgery {
func performSurgery() {
print("Success!")
}
}
// 休息
protocol HasRestTime {
func takeBreak()
}
extension HasRestTime {
func takeBreak() {
print("Time to watch TV")
}
}
// 学习
protocol NeedsTraining {
func study()
}
extension NeedsTraining {
func study() {
print("I'm reading a book")
}
}
再创建四个医院里的角色:
struct Receptionist { } // 接待员
struct Nurse { } // 护士
struct Doctor { } // 医生
struct Surgeon { } // 外科医生
然后让刚刚创建的角色遵循合适的协议:
extension Receptionist: Payable, HasRestTime, NeedsTraining {}
extension Nurse: Payable, HasRestTime, NeedsTraining, ProvidesTreatment {}
extension Doctor: Payable, HasRestTime, NeedsTraining, ProvidesTreatment, ProvidesDiagnosis {}
extension Surgeon: Payable, HasRestTime, NeedsTraining, ProvidesDiagnosis, ConductsSurgery {}
但是我们可以看到,所有的角色都遵循了Payable、 HasRestTime和NeedsTraining,上面的代码就重复了,所以我们可以再创建一个新的协议把那三个重复的协议组合起来:
protocol Employee: Payable, HasRestTime, NeedsTraining {}
extension Receptionist: Employee {}
extension Nurse: Employee, ProvidesTreatment {}
extension Doctor: Employee, ProvidesDiagnosis,ProvidesTreatment {}
extension Surgeon: Employee, ProvidesDiagnosis, ConductsSurgery{}
对扩展进行约束
例如,我们想在Employee添加一个方法:
extension Employee {
func checkInsurance() {
print("Yup, I'm totally insured")
}
}
但是checkInsurance()方法并不是所有遵循了Employee的类型都适合的,所以我们要限制那些类型可以使用checkInsurance()方法。例如我们只想让ProvidesTreatment这个类型拥有checkInsurance()方法,则可以用where来限制:
extension Employee where Self: ProvidesTreatment {
func checkInsurance() {
print("Yup, I'm totally insured")
}
}
五、MVC和MVVM
作者还另外介绍了MVC和MVVM,关于这两个概念的文章已经非常多,我就不在这写了。大家可以自行了解。
完
有任何问题,欢迎大家留言!
欢迎加入我管理的Swift开发群:536353151,本群只讨论Swift相关内容。
原创文章,转载请注明出处。谢谢!








网友评论