Ec6ed1af9bbf2c35d5cbf5ed97fa52ae
Swift 与面向协议编程

非常抱歉由于最近忙于技术书典 4 的本子的执笔,外加私事上的一些琐事的缘故,导致最近较长一段时间没有及时更新,还希望大家谅解(说的好像有人等你的更新一样😳

本文原作是之前的一个面向新人的学习会上我的一个发表,文章内容为原幻灯片欢迎戳我获取;然后同样如同以前的文章,因为我本人学习编程的地方并非在国内而且相对也较少搜索国内的资料的缘故,其实很多用词的中文并不一定准确,这种地方我会尽量标注英文原文

首先,什么是面向协议编程(Protocol Oriented)

在解释面向协议编程以前,我们需要先解释什么是面向对象编程(Object Oriented)

很久很久以前,面向对象编程还没有出现的混沌年代,上帝用编程创造了世界。有一天上帝说要有汪星人,于是世上便有了汪星人

下来上帝又说道汪星人要会叫,于是汪星人便学会了叫

这样,我们就能通过简单代码来让汪星人叫了

不过创造了汪星人的上帝并不满足,他接下来说要有喵星人,于是世上便有了喵星人

当然上帝觉得喵星人也得要会叫,于是喵星人便学会了叫

这样,我们就能通过类似的代码来让喵星人叫了

看到这里相信大家都发现了一个问题:其实不管是汪星人还是喵星人都同样是叫,发出叫声的方法其实是一样的,只是最后的叫声不一样而已;可尽管如此,我们还是需要重复写多遍发出叫声的代码,这不仅对我们的开发进度有影响,更重要的是它非常容易给我们带来 Bug

为了解决这个问题,“面向对象编程”这种手法就诞生了

面向对象编程其实内容很简单,无非就是

  • 直接为对象添加功能
    • 实现了从函数(Function)到方法(Method)的跨越(其实 Smalltalk 那时候用的是消息(Message))
  • 为对象添加继承(Inheritance)功能
    • 这样我们就能在子对象里重复利用已有的方法
  • 当然面向对象编程还有其他很多的内容这里就不一一展开了
    • 比如封装性(Encapsulation)
    • 比如多态性(Polymorphism)
    • 等等等等

于是回到刚才的代码

如果使用面向对象编程,我们就可以像这样首先定义一个“动物”的类(Class),在动物里面我们分别定义“叫声”属性(Property)和“叫”方法(Method)

然后我们就只需要继承“动物”来定义汪星人和喵星人了

这样做的好处是,我们只需要改写(Override)“叫声”属性的值,就能直接利用动物的“叫”方法来让他们叫,而不需要重复为他们各自定义同样的“叫”这个动作了,可喜可贺

不过接下来上帝又觉得太吵所以说得要有兔子,于是世上便有了不会叫的兔子

可是因为兔子继承了“动物”的缘故,它自带“叫”的方法;但是又因为它其实并不会叫,所以如果我们调用“叫”方法后果就是触发一个运行时的错误(Runtim Fatal Error)

问题还不止于此。动物们会生病,因此上帝需要一个救护车,而为了让大家能注意到救护车上帝要让救护车能发出警报,于是为了沿用动物的“叫”的功能上帝干脆让救护车继承了“动物”

像这样明明是动物却不会叫的兔子,以及明明不是动物却只是为了叫而被当作动物的救护车都是面向对象编程的常见问题

这个问题的根源,用简单的图表来说明就是这样:首先我们有一个“会叫”的“动物”类,然后汪星人、喵星人、兔子和救护车都继承了动物类,然而兔子虽然是动物但是它并不会叫;而救护车也仅管会叫但是它并不是动物

解决这个问题的一个简单的方法是在抽象的“动物”类和具体的各种动物之间再添加一个“会叫的动物”的子类,然后我们只让汪星人和喵星人继承那个子类就可以了

那兔子挺可怜的,该怎么办呢?我们干脆就为了兔子再增加一个“能认识红色的动物”类,因为兔子能识别出红色,自然兔子继承这个子类就好了,嗯看上去似乎挺不错

但是这里有两个大问题:

  1. 虽然狗的确是红绿色盲分不出红色,但是猫可以啊,然而大多数面向对象编程的语言并不允许我们多重继承(Multiple Inheritance),而且即使允许,多重继承往往也很容易给我们带来菱形问题(Diamond Problem
  2. 救护车仍然是孤零零一个人挺可怜的

这就是面向对象编程的极限

为什么会发生这样的问题呢?

  • 首先,面向对象编程的“继承”本该为“is-a”的关系
    • 也就是说,本来继承了父类的“子类”本来必须也是父类
    • 因此父类本应该专注于定义一个类别
  • 所以当我们创建“动物”这个类的时候,本应当专注于为动物下定义
    • 所以并不是所有动物都有的“叫”也好“识别出红色”也好的功能,本不应该在“动物”里面实现
    • 然而却经常有人仅仅因为“方便子类也可以用”为由给父类添加了太多的功能
    • 最终的结果当然就是所谓“上帝类(God Class)”的诞生

为了拯救废校危机解决这个面向对象编程的难题,“面向协议编程”诞生了

关于“面向协议编程”的具体说明,欢迎围观苹果的官方资料:https://developer.apple.com/videos/play/wwdc2015/408/

不过大致地简单总结一下主要有以下的特点:

  • 面向协议编程的“继承(遵循)”是 can-do 的关系
top Created with Sketch.