protocol = 协议
既然是协议,那么最基本的问题就是:
1. 协议规定了什么?(就像交通法规规定不能超速,不能闯灯之类的)
2. 谁来服从/遵守协议?(比如你在马路上跑,你就是交通法规的服从者)
一言以蔽之: ->服从协议的类至少需要实现协议中声明的属性和方法。<-
这包含了两层意思:
1. 协议的服从者是类
2. 服从协议的类必须实现协议中声明的属性和方法,这个是没商量的。除此之外允许类再实现其他的属性和方法(听着像是继承父类的感觉,但这是有区别的,我们稍后再谈)
文字堆完,来点实际的:如何使用协议?
使用协议只需要两个步骤:
1. 定义协议(先做到有法可依)
2. 让类服从协议
—>定义协议:
protocol ProtocalName {
//协议内容
func f1()->Int
func f2(_ str: String)
..........
}
可以看出协议的定义和结构的定义类似:
1. 关键字是protocol
2. 仅仅是声明方法,而不需要实现
—>服从协议:
class ClassName: ProtocalName {
//1. 实现自己的属性和方法
.........
//2. 实现ProtocalName协议中声明的属性和方法
func f1()-> Int {
......
}
func f2(_ str: String) {
........
}
}
让类服从协议也很简单,和类的继承语法相似。这个时候我们就说类ClassName服从于协议ProtocolName了
*服从协议的类 必须要实现协议中声明的属性和方法
为了加深理解,我们举个栗子
假设现在某地要举办一场运动会,运动会中同时举办的有跑步和游泳两个项目。
比赛前要检查选手的身份证,通过身份验证的选手方可参加比赛。
首先声明两个类: 类Runner和类Swimmer分别表示跑步运动员和游泳运动员,他们各自有一个方法(running和swimming)表示自己的技能。
class Runner {
//Method
func running() {
print("I can run")
}
}
class Swimmer {
//Method
func swimming() {
print("I can swimming")
}
}
比赛前一天,体育局给他们规定了一个协议,要求他们必须带身份证,第二天进场的时候必须出示身份证
于是就有了下面的协议:
//协议中声明了一个属性和一个方法
//服从这个协议的类必须实现showIDCard方法和name属性
protocol CarryIdCardProtocol {
var name:String{get}
func showIDCard()->Int
}
接下来让Runner类和Swimmer类 服从CarryIdCardProtocol协议
class Runner: CarryIdCardProtocol {
func running() {
print("I can run")
}
//实现CarryIdCardProtocol 协议规定的属性和方法
//如果不实现协议中声明的东东,编译器会报错
var name = "runnerZhang"
func showIDCard() -> Int {
//假设ID号是1
return 1
}
}
class Swimmer: CarryIdCardProtocol {
func swimming() {
print("I can swimming")
}
//实现CarryIdCardProtocol 协议规定的属性和方法
//如果不实现协议中声明的东东,编译器会报错
var name = "swimmerWan"
func showIDCard() -> Int {
//假设ID号是2
return 2
}
}
最后,神奇的地方来了! 协议还可以作为一种类型来使用
也就是说可以声明CarryIdCardProtocol类型的变量
函数可以接受CarryIdCardProtocol类型的参数
下面我们定义一个check( _ athlete: ICarryIdCardProtocol)函数,接受的就是CarryIdCardProtocol类型的参数,用以检查运动员身份
func check( _ athlete: CarryIdCardProtocol) {
let athleteID = athlete.showIDCard()
switch athleteID {
case 1: print("\(athlete.name): Runner, Checked")
case 2: print("\(athlete.name): Swimer, Checked")
default: print("Unknow identification!")
}
}
因为Swimmer类和Runner类都是服从于CarryIdCardProtocol协议的类,所以他们的对象可以作为CarryIdCardProtocol类型的参数传入check(_ :CarryIdCardProtocol)中
//创建对象
var swimmerWan = Swimmer()
var runnerZhang = Runner()
//检查运动员身份
check(swimmerWan)
check(runnerZhang)
对应的输出如下:
swimmerWan: Swimer, Checked
runnerZhang: Runner, Checked
从上面的栗子中,你看到protocol的强悍之处了吗??
1. simmerWan和runnerZhang的类型不同,但是因为他们的类都服从于CarryIdCardProtocol协议,所以都可以作为check(: CarryIdCardProtocol)的参数传入
2. Swimmer类和Runner类都明明半毛钱关系都没有,可是都实现了name属性和showIDCard()方法,难道这是巧合? 不是的,是CarryIdCardProtocol协议逼他们的
3. 总之,当你想要逼迫某个类的实现某种功能,逼迫他提供某种服务的时候,不要犹豫,给他一个protocol,让他带上这个紧箍咒吧
不论是语法还是功能,协议和继承是不是都怎么看怎么像,协议甚至还能像类一样继承! 协议和类似乎就是同一回事?
但其实他们是有本质区别的:
1. 协议只是声明了类必须要实现的属性和方法,其他的就交给类自己去实现。说白了就是给了个命令,其他啥也没有! 而类继承就不同了,父类给了子类无限的关怀,子类可以直接访问父类中允许访问的属性和方法,不需要子类再自己实现。
2. 类继承在一定程度上破坏了“低耦合”的要求,必然使父类和子类产生依赖关系。而协议就不同了,虽然Swimmer和Runner都服从CarryIdCardProtocol协议,都实现了name属性和showIDCard方法,但是,其实他们的属性和方法除了同名之外就没有什么关系了!