书籍链接:《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相关内容。
原创文章,转载请注明出处。谢谢!
网友评论