• 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
  • 相关阅读:
    BGP community和联邦实验
    BGP RR的设计原则
    BGP不可比较的AS间的度量问题的解决办法
    BGP理解错误的部署RR造成的环路
    BGP数据结构表
    BGP RR的环路避免机制
    BGP Lab RR & Loop (1)
    Lab BGP Summary
    70、对象复用的了解,零拷贝的了解
    66、malloc、realloc、calloc的区别
  • 原文地址:https://www.cnblogs.com/huanying2000/p/6422057.html
Copyright © 2020-2023  润新知