美文网首页Swift Advance
Swift面向协议编程(和面向对象的对比)-基础版

Swift面向协议编程(和面向对象的对比)-基础版

作者: Hellolad | 来源:发表于2018-03-26 00:02 被阅读50次

    引言:最近研究了一下面向协议编程,来谈一下自己的理解和使用体会.

    首先,2015年WWDC大会上,swift宣布swift2是一门支持面向协议编程的语言,当时完全不知道面向协议编程到底是什么东西,因为平时在开发项目的过程中一直都在使用面向对象的思想去编程和开发。

    其实说白了面向协议编程就是一种编程思想,只要在开发的过程中多想,多思考,你也完全可以创造出来另一种编程思想。

    在swift中,真的,协议真的是强大的不得了,他可以做的事情太多了,在我熟知的集中编程语言中,基本上除了class能遵守协议之外,其他的类型都没有遵守协议这种方式,而在swift中,class, struct, enum, protocol 都可以遵守协议,并且跟他很好的进行配合使用。

    首先我们来看一下这四种类型遵守协议的代码:

    protocol MyProtocol {}
    
    class Person: MyProtocol {}
    struct Car: MyProtocol {}
    enum NotificationType: MyProtocol {}
    protocol Equatable: MyProtocol {}
    

    这种基础的相信大家都已经非常熟悉了,下面我们来说一下协议的扩展,这个,我觉得大家都也很熟悉,但是这个确实很有用处。

    和其他类型一样,协议也可以进行扩展,可以为所有符合该协议的的类型提供公共方法

    protocol MyProtocol {}
    extension MyProtocol {
        func add_ABC(_ str: String) -> String {
            return str + "ABC"
        }
    }
    

    好处可想而知,全项目中唯独这一份代码,你不需要在你的类中去添加这些代码,只要你的类型遵守了这个协议,那么你自然就拥有了这个函数。

    exp:

    struct Person: MyProtocol {
        var name: String
    }
    
    let person = Person(name: "Henry")
    let addABCName = person.add_ABC(person.name)
    print(addABCName)
    输出: HenryABC
    

    <例子只是一个说明,无实际意义>

    接下来我们来说下,swift中我们到底如何来使用面向协议的思想来编程。

    最早以前我接触过C#, C#里面的这种东西叫委托,当时完全不知道这个东西是干什么使用的,只是老师告诉我们,这个委托,你就看做是老板,定义的函数就相当于是老板给你发的命令,他不管你会不会完成,他只是发命令的人,具体执行要你来完成。反正当时我是靠这个理解的委托的意义,不知道大家赞不赞同...

    我们都知道,现在的项目中大多数用的思想还是面向对象,我们来举个实际的例子来说一下面向对象的思想:

    首相我们来设计一个场景(请忽略我的设计·········实在不知道编什么)

    动物:Animal
    陆地动物:Dog     狗
    两栖动物:Cabrite 蜥蜴
    三栖动物:Duck 鸭子(瞎编一个)
    

    狗只能在陆地上</br>
    蜥蜴可以在陆地和水中

    鸭子可以在空中陆地水中... 有点扯了

    好了我们看代码

    enum LifeStyle {
        case land
        case water
        case air
    }
    
    class Animal {
        var lifeStyles = [LifeStyle]()
        
        var landWalk: Bool = true
        var waterSwim: Bool = true
        var airFly: Bool = true
        
        func doLandWalk() {}
        func doWaterSwim() {}
        func doAirFly() {}
        
        func isLifeStyle(style: LifeStyle) -> Bool {
            return lifeStyles.contains(style)
        }
    }
    
    class Dog: Animal {
        override init() {
            super.init()
            
            lifeStyles = [.land]
            landWalk = true
            waterSwim = false
            airFly = false
        }
        
        override func doLandWalk() {
            print("Dog Land Walk")
        }
    }
    
    class Cabrite: Animal {
        override init() {
            super.init()
            
            lifeStyles = [.land, .water]
            landWalk = true
            waterSwim = true
            airFly = false
        }
        
        override func doLandWalk() {
            print("Cabrite Land Walk")
        }
        override func doWaterSwim() {
            print("Cabrite Water Swim")
        }
    }
    
    class Duck: Animal {
        override init() {
            super.init()
            
            lifeStyles = [.land, .water, .air]
            landWalk = true
            waterSwim = true
            airFly = true
        }
        
        override func doLandWalk() {
            print("Duck Land Walk")
        }
        override func doWaterSwim() {
            print("Duck Water Swim")
        }
        
        override func doAirFly() {
            print("Duck Air Fly")
        }
    }
    
    var animals = [Animal]()
    var a1 = Dog()
    var a2 = Cabrite()
    var a3 = Duck()
    animals.append(a1)
    animals.append(a2)
    animals.append(a3)
    
    for (_, animal) in animals.enumerated() {
        if animal.isLifeStyle(style: .land) {
            print("animal Life Land")
            animal.doLandWalk()
        }
        if animal.isLifeStyle(style: .water) {
            print("animal Life Water")
            animal.doWaterSwim()
        }
        if animal.isLifeStyle(style: .air) {
            print("animal Life Air")
            animal.doAirFly()
        }
    }
    输出:
    animal Life Land
    Dog Land Walk
    animal Life Land
    Cabrite Land Walk
    animal Life Water
    Cabrite Water Swim
    animal Life Land
    Duck Land Walk
    animal Life Water
    Duck Water Swim
    animal Life Air
    Duck Air Fly
    

    正确输出了我们所定义功能

    狗仅仅在陆地生存

    蜥蜴可以在陆地和水中

    鸭子可以在水中陆地空中...(莫名的喜感)

    OK,那么问题来了?

    我觉得这样做已经很好了,面向协议的话题可以结束了,我用面向对象都能实现了为什么还要面向协议呢? 不急我们先看一下协议如何实现上面的这些东西

    exp:

    protocol Animal {
        
    }
    
    protocol LandAnimal: Animal {
        var landWalk: Bool {get}
        
        func doLandWalk()
    }
    
    protocol WaterAnimal: Animal {
        var waterSwim: Bool {get}
        
        func doWaterSwim()
    }
    
    protocol AirAnimal: Animal {
        var airFly: Bool {get}
        
        func doAirFly()
    }
    
    
    struct Dog: LandAnimal {
        let landWalk: Bool = true
        func doLandWalk() {
            print("Dog Land Walk")
        }
    }
    
    struct Cabrite: LandAnimal, WaterAnimal {
        let landWalk: Bool = true
        let waterSwim: Bool = true
        func doLandWalk() {
            print("Cabrite Land Walk")
        }
        func doWaterSwim() {
            print("Cabrite Water Swim")
        }
    }
    
    struct Duck:LandAnimal, WaterAnimal, AirAnimal {
        let landWalk: Bool = true
        let waterSwim: Bool = true
        let airFly: Bool = true
        func doLandWalk() {
            print("Duck Land Walk")
        }
        func doWaterSwim() {
            print("Duck Water Swim")
        }
        func doAirFly() {
            print("Duck Air Fly")
        }
    }
    
    var animals = [Animal]()
    var a1 = Dog()
    var a2 = Cabrite()
    var a3 = Duck()
    animals.append(a1)
    animals.append(a2)
    animals.append(a3)
    
    for (_, animal) in animals.enumerated() {
        if let dog = animal as? Dog {
            dog.doLandWalk()
        }
        if let cabrite = animal as? Cabrite {
            cabrite.doLandWalk()
            cabrite.doWaterSwim()
        }
        if let duck = animal as? Duck {
            duck.doLandWalk()
            duck.doWaterSwim()
            duck.doAirFly()
        }
    }
    输出:
    Dog Land Walk
    Cabrite Land Walk
    Cabrite Water Swim
    Duck Land Walk
    Duck Water Swim
    Duck Air Fly
    

    可以看出,首先协议的写法要比类的继承要简要很多,然后阅读起来也很方便,当然这不是一个主要的原因。

    1. 在面向对象中,我们的Dog类继承了Animal类,虽然我们知道Dog只有Lnad的属性,但是我们不可避免的一个问题就是我们的Dog是可以调用到doWaterSwimdoAirFly的,这是一个我觉得编程多年的开发也会遇到的错误,但是协议就不会,为什么,因为首先编译器就不会让你通过,因为Dog类在面向协议中并没有遵守WaterAnimal和AirAnimal
    1. 在面向对象中,我们的派生类只能把landwWalk的Book类型设置为变量,这样,我们就可以再类中做任何的更改,如果这样的话,那就会出现很多问题,但是在协议中就不会出现这种问题,首先你在定义的啥时候已经表明了 {get} 并且你可以在你的实现中用let来声明它是一个常量.

    当然面向协议还有很多的好处,在编程中改变一下思想,其实就可以做到面向协议编程。

    如果说面向协议和面向对象哪个好,我不敢说面向协议就一定比面向对象强,我只能说你的项目是否适用,当然swift的标准库中有太多的协议,可以说,swift是很推荐我们使用协议编程,所以,对于项目来说取优吧。一切以项目为主。

    当然说道协议肯定离不开泛型,这篇我文章就不做介绍了,可以看我URLNavigator使用指南及扩展这篇文章,里面有用到协议和泛型的结合使用。

    这也是我这两天理解和体会到的一些,也有很多不足的地方或者写的不好的地方,还请大家谅解,本文仅供参考,有好的意见大家尽管在下方留言。

    相关文章

      网友评论

        本文标题:Swift面向协议编程(和面向对象的对比)-基础版

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