首先我只想问:为什么是协议?为什么面向协议编程?如果我们回到过去那段年少无知少不更事的面相对象编程时期,我们很多人最初学习的是Objective-C,这意味着我们免受多继承的专横。又或者你是这个房间里另一半喜欢C++的人,那么我们并没有受过多继承的启示,我们稍后将对其进行讨论。

单继承中,层次结构是线性的:你有父辈、子辈以及孙子辈一系列的继承树。当你回到树的顶端,所有的一切有一个单独的父辈。这使得层次干净,但同时你的确失去了合理使用多继承所带来的优势。在Swift中不能继承枚举和结构类型,只有类可以。这意味着你有时需要弄得跟麻花一样来让你的类型有意义。这样最终能得到真正通用的超类。然后一级一级下来,如果你可以想象更多的级在你从图中获得一个叶子结点之前,你才能得到一个真正可以实例化和使用的类。

"你有时需要弄得跟麻花一样来让你的类型有意义"

所以通过协议,你可以使得类型系统更加有组合性,你可以理清继承的长链。当然你将要放弃一个长而高的继承链,为了一个有协议一致性的宽的链。但我认为取舍是值得的,希望在这个演讲结束后你也这么认为。

什么样的东西放进协议里有意义?我不打算谈我已经完成的很酷的协议,而是浏览一下苹果在Swift标准库中提供的协议。我们将浏览,也许你会学到一些你以前从未听过的协议。我们究竟能找到什么伟大的想法,接着也许可以获得一些灵感——在我们的代码里什么样的东西可以和协议一起用。基本上这个演讲的思路是Swift团队使用协议的方法,给我们一些可以怎么用协议的提示?

最终目标是让你开始思考协议,想出一些很酷的点子然后开源,然后我会在你GitHub的仓库上点星。

三种协议类别:"Can do","Is a"以及"Can be"

Swift标准库包括54个真正的共有协议。一开始这个演讲我开玩笑地想一个个说明它们,每个16秒来凑时间,但相反,我把它们分成三类。"Can do"协议,"Is a"协议,"Can be"协议。每次我们会看其中一个,看一些示例,再看看我们能够学到的东西。

"Can do"协议

首先我们先来看看"Can do"协议。这些描述的事情是类型可以做或已经做过的,它们也以 -able 结尾为语法,这使得当你浏览头文件时它们很容易被找到。第一个例子:一个类型遵守Hashable协议,意味着你可以得到这个类的整型散列值。这意味着你可以把它存储进一个集合,可以当作一个字典的键等等。还有Equatable和Comparable协议,这意味着你可以用Swift中各种相等和比较的运算符比较两个实例的值。这些都是很常见的协议,你可能已经在你自己的类型中实现了。你会注意到这些协议描述了你可以对类进行的操作。有比较、相等、散列。

"AbsoluteValuable(绝对有价值)。这听起来如此重要。正因为它以'valuable(价值)'结尾"

这里做一个补充说明,让我们来谈谈我认为的最好的命名协议,它值得一个特殊的过度动画:AbsoluteValuable(绝对有价值)。这听起来如此重要。正因为它以"valuable(价值)"结尾。但不幸的是它没有听起来那么重要。它只意味着支持绝对值函数。

还有一个小协议子集在这个"Can do"组中,和替代视图或替代表示形式有关。

让我们看看一个简单的例子RawRepresentable。这意味着该类可以表示成某种原始值,然后你可以把原始值转变回实际的实例。这听起来很像Swift里的枚举,有内置的原始值。所以所有有枚举的功能的类有一个初始化函数,它接受一个原始值,一旦你有一个枚举值就得到它原始值的版本。这些都建立在这个协议之上。你可以用自己的结构体和类做类似的事情,如果你喜欢。这里的想法是,东西内在的值是一样的,你只是改变它外在的表示。只因为,原始值和实例值之间存在一对一的映射。

同属此类。

接下来是CustomPlaygroundQuickLookable。这只是意味着你类型可以在playground中快速查看。同时这也意味着,你的类型是一样的,你不是将它转换为其他东西,而是为你的值提供另一种替代视图。在这种情况下,它可以在快速浏览中显示。

"所以我们有操作,我们有替代试图。从中我们可以学到什么呢?"

如果你自己的类型有操作,比如说你曾正在写下一代Instagram杀手级照片过滤APP,你可以添加一个过滤性的协议,然后让你的照片实例、图像去遵守它。假设之后,你的过滤APP火了,它真的流行起来,你想要扩展到视频。然而视频只是另一种形式的媒体。在理论上,你还可以应用过滤性的协议在视频、音频、3D照片上,无论将来出现了什么。

替代视图的例子呢?总存在从大照片创建缩略图的情况,你可以认为这是全尺寸照片的替代视图。再次,这实际上不是一个转换,它只是替代的表示形式。所以,你可以想象这样一个Thumbnailable协议,希望你能想出一个更好的名字,甚至音频版本的一个缩略图。缩略图就像一个低比特率版本的音频之类的。

这里的基本思想,是把你APP和代码中常见的操作抽象出来,协议化他们,如果有这个词。为什么你要这么做?一个好处是使得想法可重用。你有几种类型需要实现一些常见的操作,现在他们可以共享同一个有保证的公共的接口。你可以得到多态的好处,即使是在你的结构和枚举里。而且,这种复合的方法可以帮助你从操作中分割东西出来。我知道这里意见会不同,但我喜欢从这样的小块来建立一个类型,基于它们能做什么。这是第一类的协议、操作、替代视图。你可以建立的操作和视图的集合用于您的类型。

"Is a"协议

下一类是"Is a"协议,这些描述类型是什么样的。与"Can do"的协议相比,这些更基于身份。这意味着遵守多个协议,感觉很像Swift的多继承。您可以在标准库中找到这些协议,因为它们以"-type"结尾。它们占了整整一半标准库,54个中有35个左右的是这类的。让我们来看一个例子。CollectionType是个好协议。显然Array、Dictionary、Set遵守CollectionType。或许更令人惊讶的是,Ranges和String views。如果你有一个字符串,你可以获得它的UTF-8或UTF-16的表示形式。所以,它只是一系列的Unicode代码点。所以,它也遵守CollectionType。

还有一些协议包括的一些原语像IntegerTyp、FloatingPointType、BooleanType等等。这些协议更像分组。所以有几个整数类型。我们有无符号整数、有符号整数、16位整数等等。但它们都组合在一起,因为他们共同遵守整数类型的协议。如果你想出自己的整数类型,也许你想要一个4位整数或6位整数,有点非主流,那么为什么不遵守这个协议。但是,这不大可能发生。大多数这类协议你可能从来没有编写类型去遵守这些协议。例如你看BooleanType头文件的注释,实际上劝阻你创造更多的布尔类型,因为一个已足够。另一个例子是MirrorPathType,它的头文件有以下令人愉快的注释:"不要声明新的类遵守这个协议,它们不会像预期的那样工作。”

所以,正如你所看到的,这意味着许多这一类的协议,你可能是使用遵守这些的类型。我相信每个人都使用一个数组或一个整数,但你可能不会创建遵守它们的类型。虽然有一些你可能使用——我们有ErrorType,我们早些时候听Thomas说过,在Swift 2中新的错误处理模式用。还有SequenceType、GeneratorType,如果你正在构建集合化的东西且你想要支持迭代,可以看一看这些协议。

这就是"Is a"协议。协议被当作身份。我们可以从这个模式的协议中学到什么吗?再次,因为这些都是基于身份而不是操作,你可以在更大的类型分组中使用它们。回到规范化动物王国的例子:这是一个夸张的很长的类层次结构。底部甚至没有一种我们可以实例化的类型。在这个类层次结构上,每一步都比之前添加一些功能。因此,有了协议你可以让你的类型系统有更多的组合性。你有这个协议的清单,你可以构建和在不同类型中使用。比如猫叫和狗吠,更多是一种"Can do"风格的动物能做的事,而"两条腿"和"四条腿"则更多是一种身份类型。你会注意到两条腿和四条腿也有继承,因为协议可以像这样继承。

这意味着,一旦你设置好了这些协议,你可以建立起过去需要巨大的超类列表而现在只是一组协议的东西,包括继承如果你需要它。当你构建你的类型,你可以在这里选择身份和需要的功能。因为你的类型可以遵守多个协议,你可以一点点建立类型的功能,基于协议的一致性。

这就是第二类的标准库协议--"Is a"协议,与分组和身份有关。

"Can be"协议(11.28)

最后我们有"Can be"类型。这不是同一个东西的替代视图,正如我们已经看到的,这些都是直接转换。从类型X转换到Y。这些协议以"-Convertible"结尾。这意味着这个类型可以被转换到或者转换成别的东西。

让我们看看几个例子。我们有简单的初始化风格的,如FloatLiteralConvertible、IntegerLiteralConvertible、ArrayLiteralConvertible等等。如果你的类型遵守FloatLiteralConvertible那么这意味着你需要一个初始化函数,接受某种floatLiteral,默认情况下这是一个double值,然后构建你的类型。所以转换的方向是从一个浮点数到你的类型。

相比之下,有每个人的最好的朋友CustomStringConvertible之类的协议,又或如先前知道的Printable协议。它指定你的类型可以转换成一个字符串,所以转换变到另一个方向,是从你的类型中到一个字符串。

"一个Objective-C从业者看到,说'啊,那没什么。我码方法声明的时间比每次我码代码的时间都长。'"

这里再次补充说明,54个协议中名称最长的也在此类,ExtendedGraphemeClusterLiteralConvertible——41个字符。我相信那些来自Objective-C会说、或笑、就像:"啊,那没什么。我码方法声明的时间比每次我码代码的时间都长。"这就是用于转换的协议在这最后一组。我们可以从这样的协议中学到什么,除了要尽量保持你类型的名字短?

这是很明显的。如果你有类型,它可以成为其他类型,那就不要只添加一个函数,或添加一个被计算的属性,或添加一个初始化函数。考虑设置一个协议。记住你可以使用协议指定你的类型被转换到或转换成别的。所需的其他任何技术讨论的例子,除了动物,是员工数据库。如果你有对象表示人、普通员工、经理、承包商,那么这些人可能是一个单独的类型。如果承包商可以被雇佣而作为一个员工,或员工可以被晋升为经理,那这就是一种转换。你不想再加入人的名称、地址、电话号码和社会安全号等等。你想相对无缝地把一个承包商转换成员工。你可以用一个EmployeeConvertible协议。然后说承包商类型和应试者类型能遵守它。

这么做的好处是什么?为什么需要一个协议加上转换函数,而似乎仅仅一个函数不是更简单吗?再次,它一部分是组合的方法。一个应试者可以成为员工的事实,是类型是什么的一部分,但这并不特别。其他的人也可以成为员工。通过使用一个协议可以保证有一个共同的定义良好的接口来将一些人转换成一个员工。

还有一个好处是,代码漂亮的像文档一样。如果你浏览代码,或者项目里的其他人,你会看到"EmployeeConvertible",并且你已经熟悉它,它告诉了你这类型能做什么和接口是什么样子。你还可以在你的项目查找"EmployeeConvertible"这个词,然后在搜索结果中,就可以看到能成为员工的类型的列表。这就是"Can be"协议组合,处理你类型之间的转换。

四个广泛模式

所以我们看到三类来自标准库的协议,它们与能力、身份和转换有关。什么是广泛的模式,想想我们自己的代码?我们有四个:

  • 操作--如果有一组通用的操作你必须在类型中执行,考虑抽象出来当作协议。

  • 与替代视图有关--如果你的类型有替代视图,或另一种表示形式,不是一个完整的转换,想想它是否遵守公有协议。

  • 代表身份--这是你做类似多继承的地方,或混合多种类型(Mix-ins)的类型。考虑身份和类型,把相似的类型用协议来分组。

  • 最后我们有转换,无论是从一个类型转换成别的,还是一个类型被转换到,如果特定的转换在代码中多次发生,考虑抽象很常见的转换作为协议,这帮助你跟踪事物,并保持一致的接口。

我想,看到苹果把如此多的常用功能,如映射、过滤器、枚举函数、抽象到协议,使用的也只是普通的旧协议和协议扩展,这是一个很好的例子。一个未来将如何强大的灵感。苹果正遵循这个榜样。例如,如果你看看数组的定义,它遵守8个协议,字符串遵守12协议,等等。所以这里的想法是,你创建这些特征打包在协议里,然后你的你的代码库就都可以使用。

我认为以这种方式思考你的类型,可以帮助你在脑海里保持清晰和并把这些类型分类。所以我肯定鼓励在你自己的代码里尝试这些。仔细看看你的类型,聚焦于它们的共同点,看能不能用协议。

以上就是我全部要说的。协议万岁,谢谢!

Swift55个协议的分类和讲解分析的更多相关文章

  1. IOS中类的扩展(协议,分类)

    IOS中类的扩展(协议,分类) 扩展类,我们可以使用协议和分类这两种方法,下面我们来分别实现这两种方法: 参考网址:http://www.cnblogs.com/wendingding/p/37095 ...

  2. Libreswan软件的密钥协商协议IKEv1主模式实现分析

    Libreswan软件的密钥协商协议IKEv1主模式实现分析 1 协商过程 IKEv1(互联网密钥交换协议第一版)是IPsec VPN隧道协商使用的标准密钥协商协议,其协商过程如下图所示. 总共来回交 ...

  3. OSPF协议原理及配置5-LSA分析

    OSPF协议原理及配置5-LSA分析   前面,已经介绍了邻接关系的建立和LSDB的同步.通过同步过程的介绍,我们可以了解LSDB的同步是通过交互LSA实现的. 不同角色的路由器发出的LSA的内容是不 ...

  4. pyhanlp文本分类与情感分析

    语料库 本文语料库特指文本分类语料库,对应IDataSet接口.而文本分类语料库包含两个概念:文档和类目.一个文档只属于一个类目,一个类目可能含有多个文档.比如搜狗文本分类语料库迷你版.zip,下载前 ...

  5. Logistic回归分类算法原理分析与代码实现

    前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...

  6. effective OC2.0 52阅读笔记(四 协议与分类)

    23 通过委托与数据源协议进行对象间通信 总结:委托模式的常规委托模式中,信息从类Class流向受委托者delegate.数据源模式,信息从数据源datasource流向class.数据源和受委托者可 ...

  7. 流媒体学习二-------SIP协议学习(基本场景分析 )

    作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/ 1.SIP业务基本知识 1.1 业务介绍 会话初始协议(Session Initiation Protocol) ...

  8. TCP协议可靠性数据传输实现原理分析

    http://blog.csdn.net/chexlong/article/details/6123087 TCP 协议是一种面向连接的,为不同主机进程间提供可靠数据传输的协议.TCP 协议假定其所使 ...

  9. Objective-C Runtime 运行时之五:协议与分类

    Objective-C中的分类允许我们通过给一个类添加方法来扩充它(但是通过category不能添加新的实例变量),并且我们不需要访问类中的代码就可以做到. Objective-C中的协议是普遍存在的 ...

随机推荐

  1. 64位Win7下安装与配置PHP环境【Apache+PHP+MySQL】

    [软件下载] 本安装实例所使用安装文件如图所示: 其中,64位版本的MySQL安装文件mysql-5.5.33-winx64.msi,可直接从官网下载,下载地址:http://dev.mysql.co ...

  2. java中的vo 、dto 、dao--转

    原文地址:http://yinchunjian.iteye.com/blog/758196 O是跟数据库里表的映射,一个表对应一个VO DAO是用VO来访问真实的表,对数据库的操作都在DAO中完成 B ...

  3. [linux]记录如何设置一个新的vps

    背景 我正在做一个小项目,做好了打算上线,所有需要买个服务器,看了一圈,发现还是卖个vps合算.买了之后,进行了一些列的设置,这里记录一下,以便后面查看. 系统: ubuntu 内存:1G 一.更改时 ...

  4. 利用session做国际化引起的old区内存爆满及修复方法

    题记:昨天加班打车回家,看见前面有辆路虎在高速上开的巨慢,挡住了我坐的出租车的路,于是就跟司机吐槽了一句:“前面这车怎么这么面啊?”,司机沉默了大概3秒,说了一句富含哲理性的话:“没有面车,只有面人” ...

  5. 【转】Bloom Filter布隆过滤器的概念和原理

    转自:http://blog.csdn.net/jiaomeng/article/details/1495500 之前看数学之美丽,里面有提到布隆过滤器的过滤垃圾邮件,感觉到何其的牛,竟然有这么高效的 ...

  6. SQL各种连接查询详解(左连接、右连接..)

    一.交叉连接(cross join) 交叉连接(cross join):有两种,显式的和隐式的,不带on子句,返回的是两表的乘积,也叫笛卡尔积. 例如:下面的语句1和语句2的结果是相同的.语句1:隐式 ...

  7. AEAI Portal V3.5.2门户集成平台发版说明

    AEAI Portal门户集成平台为数通畅联的核心产品,本着分享传递的理念,数通畅联将Portal_server.Portal_portlet两个项目开源,目的在于满足客户与伙伴的OEM需求,以及为广 ...

  8. 【jQuery基础学习】00 序

    作为一个从来没有认真学过jQuery的菜来讲,我所学的都是jQuery基础. 算是让自己从0开始系统学一遍吧.学习书籍为:<锋利的jQuery>. 虽然是个序,表示一下我是个菜,但还是来几 ...

  9. Android开发总是难以入门

    发现自己很难入门,是真的太难,还是自己主观拒绝.

  10. 51Node 1364--- 最大字典序排列(树状数组)

    51Node  1364--- 最大字典序排列(树状数组) 1364 最大字典序排列 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 给出一个1至N ...