美文网首页
每天学一点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