在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: , losses: )
print(teamRecord) let baseball = baseballRecord(wins: , losses: )
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 >
}
} 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: )
let a = Student(name: "Alice", score: )
let b = Student(name: "Bob", score: )
let c = Student(name: "Karl", score: ) 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 >
}
} 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: )
let a = Student(name: "Alice", score: )
let b = Student(name: "Bob", score: )
let c = Student(name: "Karl", score: ) let students = [a,b,c,tian] func topOne<T:Comparable>(seq:[T]) ->T {
assert(seq.count > )
return seq.reduce(seq[]){
max($, $)
}
}
topOne(seq: [,,,]) 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 学习笔记(面向协议编程)的更多相关文章

  1. Spring学习笔记--面向切面编程(AOP)

    什么是AOP AOP(Aspect Oriented Programming),意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的 ...

  2. swift学习笔记之-协议

    //协议(Protocols) import UIKit /*协议(Protocols) 1.协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法.属性,以及其他需要的东西 2.类.结构体或枚 ...

  3. 为什么说swift是面向协议编程--草稿

    为什么说swift是面向协议编程 public protocol ReactiveCompatible { /// Extended type associatedtype CompatibleTyp ...

  4. Swift -POP( 面向协议编程)与OOP(面向对象编程)

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

  5. fir.im Weekly - 揭秘 iOS 面向协议编程

    本期 fir.im Weekly 重点推荐关于 iOS 面向协议编程相关文章,还有 iOS 多线程安全.Swift 进阶.Android MVVM 应用框架.Android 蓝牙实践等技术文章分享和工 ...

  6. 孙鑫VC学习笔记:多线程编程

    孙鑫VC学习笔记:多线程编程 SkySeraph Dec 11st 2010  HQU Email:zgzhaobo@gmail.com    QQ:452728574 Latest Modified ...

  7. WCF学习笔记之事务编程

    WCF学习笔记之事务编程 一:WCF事务设置 事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元: WCF通过System.ServiceModel.TransactionFlowA ...

  8. Spring实战第四章学习笔记————面向切面的Spring

    Spring实战第四章学习笔记----面向切面的Spring 什么是面向切面的编程 我们把影响应用多处的功能描述为横切关注点.比如安全就是一个横切关注点,应用中许多方法都会涉及安全规则.而切面可以帮我 ...

  9. 编程范式 --- 面向协议编程(Protocol Oriented Programming,简称POP)

    面向协议编程(Protocol Oriented Programming,简称POP) 是Swift的一种编程范式,Apple于2015年WWDC踢出 在Swift的标准库中,能见到大量POP的影子 ...

随机推荐

  1. CF917C Pollywog —— 状压DP + 矩乘优化

    C. Pollywog 题目描述 原题题目链接.题目大意为:有$x$只蝌蚪,在$n$个石头中的最左端的$x$个石头上,这$n$个石头是在同一直线上的.每一次只能最左边的一个蝌蚪进行跳跃,并且只能跳$1 ...

  2. luogu P3147 [USACO16OPEN]262144

    题目描述 Bessie likes downloading games to play on her cell phone, even though she doesfind the small to ...

  3. 你知道如何在springboot中使用redis吗

    特别说明:本文针对的是新版 spring boot 2.1.3,其 spring data 依赖为 spring-boot-starter-data-redis,且其默认连接池为 lettuce ​  ...

  4. 终端应用变身文件 MD5/SHA1 校验工具

    担心下载的文件被恶意篡改?没有找到 Mac 平台文件校验工具?其实 Mac OS X 系统中已经内置了“文件 MD5/SHA1 校验工具”,它就藏身于终端(Terminal)应用中! 打开终端应用,输 ...

  5. mysql----乐观锁总结和实践

    悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这 ...

  6. http://blog.csdn.net/LANGXINLEN/article/details/50421988

    GitHub上史上最全的Android开源项目分类汇总 今天在看博客的时候,无意中发现了 @Trinea在GitHub上的一个项目 Android开源项目分类汇总, 由于类容太多了,我没有一个个完整地 ...

  7. Flume NetCat Demo

    准备工作: 1.apache官网下载flume 2.解压flume 3.修改flume-env.sh,配置JAVA_HOME NetCat采集Demo: 1.在conf中创建netcat-logger ...

  8. 13.2 处理静态资源【从零开始学Spring Boot】

    转载:http://blog.csdn.net/linxingliang/article/details/51637052目录(?)[-] 默认资源映射 自定义资源映射 自定义目录 使用外部目录 通过 ...

  9. Spring IOC源代码具体解释之整体结构

    Spring ICO具体解释之整体结构 IOC介绍 IOC, spring的核心.贯穿Spring始终.直观的来说.就是由spring来负责控制对象的生命周期和对象间的关系,将对象之间的关系抽象出来. ...

  10. 怎样通过Html网页调用本地安卓app

    怎样使用html网页和本地app进行传递数据呢?经过研究.发现还是有方法的,总结了一下,大致有一下几种方式 一.通过html页面打开Android本地的app 1.首先在编写一个简单的html页面 & ...