在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
本人已迁移博客至掘进,以后会在掘进平台更新最新的文章也会有更多的干货,欢迎大家关注!!!https://juejin.im/user/588993965333309
面向协议编程(Protocol Oriented Programming,简称POP),是Swift的一种编程范式,Apple于2015年WWDC提出的,如果大家看Swift的标准库,就会看到大量POP的影子。 同时Swift也是一门面向对象的编程语言(Object Oriented Programming,简称OOP),在Swift开发中,OOP和POP是相辅相成的,任何一方并不能取代另一方。 今天我们重点讲解下面向协议编程(POP)在Swift下的使用 回顾OOPOOP的三大特性:封装、继承、多态 继承的经典使用场合 当多个类(比如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想到的一些解决方案?
POP的解决方案 protocol Runnable { func run() } extension Runnable { func run() { print("run") } } class BVC: UIViewController, Runnable{} class DVC: UITableViewController, Runnable{} POP的注意点
实例-使用协议实现前缀效果统计字符串有几个数字出现,例如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") } } 这样就比较顺利较完美的解决了问题,又很好的拓展了功能!!!
总结以后要给某一个类扩展功能,可采取下面步骤
|
请发表评论