Swift 学习笔记(面向协议编程)
Posted 幻影-2000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 学习笔记(面向协议编程)相关的知识,希望对你有一定的参考价值。
在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程的。
扩展协议和默认实现
protocol Record { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double } struct BasketballRecord:Record,CustomStringConvertible { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) } } struct baseballRecord:Record,CustomStringConvertible { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) } } let teamRecord = BasketballRecord(wins: 2, losses: 10) print(teamRecord) let baseball = baseballRecord(wins: 3, losses: 10) print(baseball)
我们可以看到 这两个结构体 都分别继承了Record 和 CustomStringConvertible协议 其中第一个是我们自定义的协议 第二个是系统协议,在Swift中协议也是可以继承的,于是我们可以改写成下面的模式。
protocol Record:CustomStringConvertible { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double } struct BasketballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) } } struct baseballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) } }
你会看到还是有冗余的代码 就是遵守CustomStringConvertible协议 实现的description的返回时一样的,这个时候我们就像进一步封装,那么我们该怎么做呢?这个其实就用到我们所说:协议是可以扩展的,而且在扩展中协议的属性和方法是可以有默认实现的,我们可以这样写:
protocol Record:CustomStringConvertible { var wins: Int{get} var losses:Int{get} func winningPercent() -> Double } //扩展协议 extension Record { var description: String { return String.init(format: "WINS: %d, LOSSES: %d", [wins,losses]) } } struct BasketballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } } struct baseballRecord:Record { var wins: Int var losses: Int func winningPercent() -> Double { return Double(wins)/Double(wins + losses) } }
这样写是不是就方便多了呢,但是仔细观察 我们在遵守协议的各个结构体中是不是还有逻辑类似,但是写了好几遍的代码呢,我们是不是也可以考虑,将计算胜率的方法也迁移到扩展中呢?
protocol Record:CustomStringConvertible { var wins: Int {get} var losses:Int {get} } //扩展协议 extension Record { var description: String { return String.init(format: "wins: %d, losses:%d", [wins,losses]) } var gamePlayed:Int { return wins + losses } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } } struct BasketballRecord:Record { var wins: Int var losses: Int } struct baseballRecord:Record { var wins: Int var losses: Int }
是不是更加简便了呢,那么假如一场比赛既有输赢,又有打平的时候呢,我们新增加一个协议,当遵守了不同的协议,他们执行的默认方法,就是既满足了有输赢又可以打平里面扩展的方法的默认实现,如果只遵守了一个Record协议,则执行扩展Record中的默认实现。
protocol Record:CustomStringConvertible { var wins: Int {get} var losses:Int {get} } //打平的协议 protocol Tieable { var ties:Int {get set} } //扩展即遵守了Record协议的又遵守了Tieable协议 extension Record where Self:Tieable { var gamePlayed:Int { return wins + losses + ties } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } } //扩展协议 extension Record { var description: String { return String.init(format: "wins: %d, losses:%d", [wins,losses]) } var gamePlayed:Int { return wins + losses } func winningPercent() -> Double { return Double(wins)/Double(gamePlayed) } } struct BasketballRecord:Record { var wins: Int var losses: Int } struct baseballRecord:Record { var wins: Int var losses: Int } //可以平局的 struct FootBallRecord:Record,Tieable { var wins: Int var losses: Int var ties: Int }
协议聚合
语法结构
协议1 & 协议2
示例代码
//判断是否可以获得奖励的协议 protocol Prizable { func isPrizable() -> Bool } func award(prizable: Prizable & CustomStringConvertible){ if prizable.isPrizable() { print(prizable) print("你可以获奖") }else{ print("您不可以获奖") } }
表示这个函数的参数 即遵守Prizable协议,也遵守了CustomStringConvertible的协议。
泛型约束
struct Student:CustomStringConvertible,Equatable,Comparable,Prizable{ var name:String var score:Int var description: String { return name } func isPrizable() -> Bool { return score > 60 } } func == (s1:Student,s2:Student)->Bool { return s1.score == s2.score } func < (s1:Student,s2:Student) ->Bool { return s1.score < s2.score } let tian = Student(name: "tian", score: 90) let a = Student(name: "Alice", score: 80) let b = Student(name: "Bob", score: 67) let c = Student(name: "Karl", score: 66) let students = [a,b,c,tian] //报错 原因是因为Comparable 这个协议的实现中自己调用了自己 此时这种协议不能当作一种类型 在这种情况下我们可以改为下面的代码 func topOne(seq:[Comparable]) ->Comparable { }
为了解决上面的错误,我们可以这样写
struct Student:CustomStringConvertible,Equatable,Comparable,Prizable{ var name:String var score:Int var description: String { return name } func isPrizable() -> Bool { return score > 60 } } func == (s1:Student,s2:Student)->Bool { return s1.score == s2.score } func < (s1:Student,s2:Student) ->Bool { return s1.score < s2.score } let tian = Student(name: "tian", score: 90) let a = Student(name: "Alice", score: 80) let b = Student(name: "Bob", score: 67) let c = Student(name: "Karl", score: 66) let students = [a,b,c,tian] func topOne<T:Comparable>(seq:[T]) ->T { assert(seq.count > 0) return seq.reduce(seq[0]){ max($0, $1) } } topOne(seq: [4,5,7,8]) func topPrizableOne<T:Comparable & Prizable>(seq:[T]) ->T? { return seq.reduce(nil) { (tempTop:T?,contender:T) in guard contender.isPrizable() else { return tempTop } guard let tempTop = tempTop else { return contender } return max(tempTop, contender) } } topPrizableOne(seq: students)?.name
以上是关于Swift 学习笔记(面向协议编程)的主要内容,如果未能解决你的问题,请参考以下文章