zoukankan      html  css  js  c++  java
  • Swift -POP( 面向协议编程)与OOP(面向对象编程)

    面向协议编程(Protocol Oriented Programming,简称POP),是Swift的一种编程范式,Apple于2015年WWDC提出的,如果大家看Swift的标准库,就会看到大量POP的影子。

    同时Swift也是一门面向对象的编程语言(Object Oriented Programming,简称OOP),在Swift开发中,OOP和POP是相辅相成的,任何一方并不能取代另一方。

     今天我们重点讲解下面向协议编程(POP)在Swift下的使用

    回顾OOP

    OOP的三大特性:封装、继承、多态

    继承的经典使用场合

    当多个类(比如A、B、C类)具有很多共性时,可以将这些共性抽取到一个父类(比如D类),最后A、B、C类继承D类

    OOP的不足

    但有些问题,使用OOP并不能很好的解决问题,比如如何将BVC、DVC的公共方法run抽取出来?

    class BVC: UIViewController{
        func run() {
            print("run")
        }
    }
    
    class DVC: UITableViewController{
        func run() {
            print("fun")
        }
    }

    基于OOP想到的一些解决方案?

    1. 将run方法放到另一个对象A中,然后BVC、DVC拥有A属性--多了一些额外的依赖关系
    2. 将run方法增加到UIViewController分类中--UIViewController会越来越臃肿,而且会影响它的其它所有子类
    3. 将run方法抽取到新的父类,采用多继承?Swift不支持多继承-(C++支持多继承)

    POP的解决方案

    protocol Runnable {
        func run()
    }
    
    extension Runnable {
        func run() {
            print("run")
        }
    }
    
    class BVC: UIViewController, Runnable{}
    class DVC: UITableViewController, Runnable{}

    POP的注意点

    • 优先考虑创建协议,而不是父类(基类)
    • 优先考虑值类型(struct, enum),而不是引用类型(class)
    • 巧妙利用协议拓展功能
    • 不要为了面向协议而实用协议

    实例-使用协议实现前缀效果

    统计字符串有几个数字出现,例如1234dafdaf1234,应该返回数字8?

    1、如果在平常一处用到,可能大家直接会写一个对象方法,然后调用一下,即可计算出,如下:

    func numberCount(_ str: String) -> Int {
        var count = 0
        for c in str where ("0"..."9").contains(c) {
            count += 1
        }
        return count
    }

    通过调用self.numberCount("1234dafdaf1234")得出结论

     2、通过上面需求,可以得出是字符串的拓展功能,因此想到另外一种对字符串进行拓展extension String,计算属性相当于方法

    extension String {
        ///计算属性===方法,下面两种完全等价
        //方法
        func numberCount() -> Int {
            var count = 0
            for c in self where("0"..."9").contains(c) {
                count += 1
            }
            return count
        }
        
        //计算属性
        var numberCount1: Int {
            var count = 0
            for c in self where ("0"..."9").contains(c) {
                count += 1
            }
            return count
        }
        
    }
    print("1234dafdaf1234".numberCount())

    3、通过上面的已经可以很好的解决问题啦,对于要求很高的团队,上面还是有一些问题的,比如,上面是对系统的String进行拓展,如果定义的计算属性和系统的属性名字相同咋办,针对这个问题,可以有,在numberCount前面加入项目简称----(计算属性的本质是方法,要与存储属性分别开,不能为extension添加存储属性,如果要想添加,建立关联添加)

    extension String {
        ///计算属性===方法,下面两种完全等价
        //方法
        func hcc_NumberCount() -> Int {
            var count = 0
            for c in self where("0"..."9").contains(c) {
                count += 1
            }
            return count
        }
        
        //计算属性
        var hccNumberCount1: Int {
            var count = 0
            for c in self where ("0"..."9").contains(c) {
                count += 1
            }
            return count
        }
        
    }
    print("1234dafdaf1234".hccNumberCount1)

    可以解决上面遇到的问题,但是不够优雅,也不符合Swift的风格,Swift中有大量协议的使用,如果有协议的加入,可以比较优雅的实现

    是否可以实现"1234dafdaf1234".hcc.numberCount?

    (因为是“”.hcc,所以对字符串拓展了一个属性hcc,而hcc.numberCount又是hcc类的一个属性,所以如下)

    struct HCC {
        var string: String
        init(_ str: String) {
            self.string = str
        }
        var numberCount: Int {
            var count = 0
            for c in string where ("0"..."9").contains(c) {
                count += 1
            }
            return count
        }
    }
    
    extension String {
        var hcc: HCC {return HCC(self)}//传值self字符串
    }
    
    print("1234dafdaf1234".hcc.numberCount)

    4、上面已经完成对字符串的拓展功能的系列,也已经很好的很优雅的解决了问题,但是如果相对字符串拓展一个功能的话,这就OK啦

    如果想对数组进行拓展一个类似的方法,还要在HCC里面增加array属性和初始化以及拓展Array功能,就会发现冗余代码太多,且不够封装,不够通用

    这时候泛型的作用就来啦,如下

    struct HCC<Base> {
        var base: Base
        init(_ base: Base) {
            self.base = base
        }
    }
    
    extension String {
        var hcc: HCC<String> {HCC(self)}
    }
    
    class Person{}
    extension Person {
        var hcc: HCC<Person> {HCC(self)}
    }
    
    extension HCC where Base == String {
        var numberCount: Int {
            var count = 0
            for c in base where("0"..."9").contains(c){
                count += 1
            }
            return count
        }
    }
    
    extension HCC where Base == Person {
        func run() {
            print("run")
        }
    }
    
    "1234dafdaf1234".hcc.numberCount
    Person().hcc.run()

    效果图如下

     5、上面实现了通过类的对象调用,可不可以实现通过类本身来调用呢,因为我在使用类.hcc的时候,并不想出现类对象的属性,只想出现类型本身的方法和属性,这就需要用到static来修饰

    struct HCC<Base> {
        var base: Base
        init(_ base: Base) {
            self.base = base
        }
    }
    
    extension String {
        var hcc: HCC<String> {HCC(self)}
        static var hcc: HCC<String>.Type {HCC<String>.self}
    }
    
    class Person{}
    extension Person {
        var hcc: HCC<Person> {HCC(self)}
    }
    
    extension HCC where Base == String {
        var numberCount: Int {
            var count = 0
            for c in base where("0"..."9").contains(c){
                count += 1
            }
            return count
        }
        
        static func test() {
            print("test")
        }
    }
    
    extension HCC where Base == Person {
        func run() {
            print("run")
        }
    }
    
    "1234dafdaf1234".hcc.numberCount
    Person().hcc.run()
    String.hcc.test()

    完成上面需求!

    6、但是如果要再次增加一个Dog类,也要在Dog类中有

    var hcc: HCC<String> {HCC(self)}
    static var hcc: HCC<String>.Type {HCC<String>.self}

    这些代码,增加其他,会导致代码还是会有点冗余,这样就发现了POP的好处-是面向协议编程,将公共的地方抽出来(协议只能声明一些东西,想扩充一些东西,就是在extension加入)

    ///前缀类型

    struct HCC<Base> {

        var base: Base

        init(_ base: Base) {

            self.base = base

        }

    }

    ///利用协议扩展前缀属性

    protocol HCCCompatible {}

    extension HCCCompatible {

        var hcc: HCC<Self> {HCC(self)}

        static var hcc: HCC<Self>.Type {HCC<Self>.self}

    }

    ///给字符串扩展功能

    //让String拥有前缀属性

    extension String: HCCCompatible {}

    //给string.hcc以及String().hcc前缀扩展功能

    extension HCC where Base == String {

        var numberCount: Int {

            var count = 0

            for c in base where("0"..."9").contains(c){

                count += 1

            }

            return count

        }

        static func test() {

            print("test")

        }

    }

    class Person{}

    extension Person: HCCCompatible{}

    class Dog{}

    extension Dog: HCCCompatible{}

    extension HCC where Base == Person {

        func run() {

            print("run")

        }

    }

    这样就比较顺利较完美的解决了问题,又很好的拓展了功能!!!

    总结

    以后要给某一个类扩展功能,可采取下面步骤

    1. 定义一个前缀类型(如上面的hcc等)
    2. 定义一个协议(protocol)
    3. 遵守该协议即可
  • 相关阅读:
    NOsql总结
    关于Swift中的指针的那些事
    并发控制的概念
    并发控制--Concurrency control--乐观、悲观及方法
    数据库的三大系统
    数据库沉思录
    代码结构化(分层)阅读
    代码阅读困难的原因
    数据库锁与并发
    SQLite事务、错误与自动回滚
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/12359303.html
Copyright © 2011-2022 走看看