面向协议编程的一些思考

2,843 阅读5分钟

本文是我在团队内部分享的ppt中摘出来的,所以可能节奏有点快。

用了Swift很久也没有踏入POP的大门

并且充满了误解

  • POP是Swift提出的一个全新理念
  • POP就是狂用Protocol
  • POP站在OOP的鄙视链上游

从电视剧的最后一集开始看,所以看不懂

之后改变了学习策略

  • 【溯源】编程范式发展历史(电视剧的第一集)
  • 【横评】别的语言也有相似概念
  • 【解构】分析Swift源码的设计

最初的编程范式—结构化编程

最初的语言充满了goto,goto是强大的,但是代价是巨大的

via http://ziogeek.com/wp-content/uploads/2013/07/spaghetti.jpg

最初的编程范式—结构化编程

直到有人提出结构化编程,来限制goto的权力

这几个基本的控制流奠定了后世各种语言的基调

但是结构化编程只解决了函数执行的复杂度,而数据还是乱的不行 这促使一个新的理念诞生了:Object-Oriented Programming

via http://www.kamyacademy.com/wp-content/uploads/2014/01/object-orientated-programming-langs.png

一个伟大思想的诞生

面向对象有三个特性解决过去混乱不堪的数据存放,也被称为OOP三原则:

  • 数据抽象 Abstraction
    数据封装提供了一个信息隐藏的机制,让一个类黑盒化,这种设计减少了人们理解一块代码的难度。

  • 继承 Inheritance
    继承提供了共享代码的方式,不同于另一个世界线的原型链。

    JS原型链

  • 多态性 Polymorphism
    多态提供了针对父类的算法可以直接应用到子类上。

过去的数据存放虽然混乱,但是非常灵活,OOP则对这种能力加以限制(如同控制流对goto的限制)

简单和灵活的辩证关系

via https://www.success.com/sites/default/files/styles/article_main/public/main/articles/Find%20Balance.jpg?itok=pQrQxtxY

成也继承,败也继承

OOP在蓬勃发展之后,出现了两个分支,单一继承和多继承。前者代表是JAVA,后者是C++。 多继承首先暴露出很严重的问题:著名的The Diamond Problem

via https://en.wikipedia.org/wiki/Multiple_inheritance

其次,多继承会让你的代码结构混乱不堪

via http://public.beuth-hochschule.de/~solymosi/veroeff/objektdiagramme/bilder/Multip2.jpg

单一继承虽然避免了这个问题,但是他引起另一个问题:不够用!从多个类共享代码是一个钢需!

一般的单一继承语言只好选择组合(composition),但是组合引起不必要的层级和依赖。主要是用起来很麻烦。

所以Java在第8版的时候选择一条少有人走的路,Mix-in范式,Java里叫接口扩展(interface extension)。

Mix-IN是何方神圣?

Mix-in也是比较古老的范式,它是被近代的Ruby(1995)发扬光大。

Mix-in的解决思路是:既然多继承不好,但是想共享代码,那么就用重重约束允许某种受限的多继承存在。

于是简单和自由的取舍又出现了

Mix-in一般分为traits和接口扩展两个流派,Ruby选择是前者,而Java选择加强他本来就有的pure interface,让接口可以提供默认的方法实现,来完成和traits一样的功能性。(这一点和Swift的发展路线是一致的)

实现Mix-in只需要这一个小小的改动,但是对整个软件设计模式都产生了深远影响。

Mix-IN加入后的新世界

因为Mix-in提供了功能实现,这些代码就可以当做一种组件,组合到任意的类里,从而实现了类似多继承的代码复用。

软件架构不再是一尘不变的继承+类组合,从此有了新的样貌:

单一继承树+Mix-in注入通用的功能性

重点来了

Swift的POP就是Mix-in -> Java interface extension的延续,只不过改了名字叫protocol extension。

那充其量也就是Java的那种样貌,怎么能上升到Oriented的程度?

答案都在Swift的源码中。

Swift的野望

我们来看一下Swift对Int的实现

你没看错,除了Int本人是一个struct(甚至不是class)其它全都是Protocol! 谁还敢说不是Protocol-Oriented

归根结底:Swift的POP到底是在说什么?

Mix-in既然已经被证实是OOP的一个好的发展方向,Swift不但选择引入Mix-in,并且把它提高到核心教义,并且用这个思想搭建起Swift语言本身。

可以说Swift不是Java那样觉得Mix-in是OOP的补充,而是试图证明Mix-in可以代替Class Inheritance成为优选的范式。

连名字都改了不是吗,OOP都不要了。

消除误解

  • POP是Swift提出的一个全新理念
    不是,他是古老的Mix-in,并且是被很多现代语言应用。

  • POP就是狂用Protocol
    不是,重点在于继承架构是否是围绕Protocol设计的。

  • POP站在OOP的鄙视链上游
    POP本身就是OOP的演化,只是在OOP(99%)的基础上又迈进了一小步(1%)。

Swift走出的新路:POP之后的mix-in

通过Swift源码结构可以看出一个POP的软件产生了大量的组件

具体类型(class/struct/enum)用来组合各种组件

甚至核心逻辑也是某一级的Protocol来组合,而具体类型只是一个能new出来的门面。

软件设计的重心不再是建模对象,而是划分能力。

POP符合编程语言的发展趋势

父类和协议是OOP能提供的最高级抽象。他们是类的元类型。

POP提倡的就是在更高抽象层级上编程。

毕竟,越远离goto,代码就越简单。