美文网首页
每天学一点Swift----面向对象下(七)

每天学一点Swift----面向对象下(七)

作者: 冯可乐同学 | 来源:发表于2017-06-11 19:26 被阅读8次

十一.使用协议作为类型

1.协议也相当于一种类型,与枚举、结构体、类相比,协议相当于一种抽象的类型,它被彻底抽象成只定义规范,不负责实现。因此定义协议之后,就可以像枚举、结构体、类那样当作类型来使用,只是协议不能直接用于创建实例,协议可以做如下方面的用途:

(1)可使用协议声明变量

(2)可使用协议作为函数、方法、构造器的形参类型、返回值类型

(3)可使用协议作为is、as等运算符的***后***一个操作数

2.举个栗子:

protocol Eatable

{

//定义实例方法

Func taste()

//协议使用class修饰类型方法

class func test(msgs : String…)

}

//实现Eatable协议

struct Pie : Eatable

{

var weight : Double

//定义实例方法

func taste()

{

print(“饼干很好吃。。。”)

}

//结构体使用static修饰类型方法

static func test (msgs : String…)

{

print(“test method”)

for msg in msgs

{

print(“msg is: ”\(msg))

}

}

}

class Apple : Eatable

{

var name : String

init(name : String)

{

self.name = name

}

//定义实例方法

func taste()

{

print("苹果很好吃")

}

//类使用class修饰类型方法

class func test (msgs : String...)

{

print("apple test")

}

}

//使用Eatable声明变量,将Apple实例赋值给food,这是向上转型

var food1 : Eatable = Apple(name : "红富士")

//使用Eatable声明变量,将Pie实例赋值给food,这是向上转型

var food2 : Eatable = Pie(weight : 1.2)

//分别调用food1,food2里面的方法,这是多态

food1.taste()

food2.taste()

//定义一个函数,该函数的形参是个数可变的Eatable类型的形参

func eat(foods : Eatable...)

{

for food in foods

{

food.taste()

}

}

//由于该函数的参数要求是Eatable类型,所以既可以传入Apple,也可以传入Pie

eat(Apple(name : "apple"), Pie(weight : 2.2))

//声明并反问Eatable类型的数组

var foodArray : [Eatable] = [Apple(name : "apple1"), Pie(weight : 1.2),Apple(name : "apple2"), Pie(weight : 2.2),Apple(name : "apple3"), Pie(weight : 3.2),Apple(name : "apple4"), Pie(weight : 4.2)]

for food in foodArray

{

if let ap = food as? Apple

{

print("这个Eatable是苹果,名字为:\(ap.name)")

}

else let pie = food as? Pie

{

print("这个Eatable是饼干,重量为: \(pie.weight)")

}

}

3.通过上面可以看出,实现某个协议时,也集成某个类的本质是一样的,协议的实现类型,也相当于协议的特殊子类,因此协议实现类型的实例,完全可以当成协议实例使用。

4.一般来说,程序通常应该面向协议编程,就像其他语言倡导的面向接口编程一样,面向协议编程能提供更好的灵活性,这也是多态的价值所在。

十二.合成协议

1. Swift还允许将多个协议合成一个临时的类型,这种用法被为合成协议。合成协议的语法格式为:

protocol<协议1,协议2,协议3,....>

2.对于采用这种合成协议声明的变量、定义的参数、声明的返回值,必须同时实现合成协议里面的所有协议。

十三.通过扩展为已有的类型添加协议

1.前面已经知道通过扩展可以为已有的类型添加计算属性、方法、下标、构造器等。不仅如此,使用扩展还可以为已有的类型添加协议。

2.举个栗子:下面的代码通过扩展让String实现Eatable协议。

extension String : Eatable

{

//实现Eatable协议中的方法

func taste()

{

print("\(self) taste")

}

class func test()

{// ....}

}

3.在某些极端情况下,如果已有类型已经实现了协议中的要求,则可以更简单地通过扩展让该类型实现这个协议————此时扩展的花括号内不需要任何代码

4.举个栗子:

protocol Emptyable

{

var isEmpty : Bool {get}

}

extension String : Emptyable{}

//定义一个方法,该方法需要Emptyable参数

func foo(arg: Empayable)

{

print("arg is empty or not : (\arg.isEmpty)")

}

//调用foo方法,传入String即可,(因为String实现了Emptyable协议)

foo("abc")

foo("")

十四.唯类协议

1. Swift还支持定义一种唯类协议,这种协议**只能被类实现,不能被枚举、结构体实现,如果程序中使用枚举、结构体实现唯类协议,编译器会报错。

2.定义唯类协议非常简单,只要在定义协议的协议名后面的冒号后面紧跟class关键字即可(class放在所有父协议的第一位):

protocol协议名:class,父协议1,父协议2,...

{

//唯类协议的定义。

}

3.唯类协议中无须定义mutating方法(定义了也没用,因为只有类才能实现唯类协议,类的方法本身就可以修改实例属性),除此之外,唯类协议与普通协议基本相同。

4.使用唯类协议的优势在于:Swift总是将唯类协议当成引用类型处理,而不会当成值类型处理。这是因为唯类协议的实现者只能是类,因此肯定是引用类型。

5.举个栗子:

protocol Movable : class

{

func move()

}

class Car : Movable

{

func move()

{

print("move in car")

}

}

struct Bee : Movable----这里将会报错

{

func move()

{

print("move in bee")

}

}

var move : Movable? = nil

上面的代码中,由于Movable是一个唯类协议,因此系统可以直接将move变量当成引用类型处理。

相关文章

网友评论

      本文标题:每天学一点Swift----面向对象下(七)

      本文链接:https://www.haomeiwen.com/subject/cptkqxtx.html