摘要:Scala 并不仅仅只给 JVM 引入了函数概念,它还为我们提供了一种对于面向对象语言设计的现代视角。在这一期的 面向 Java 开发人员的 Scala 指南 中,Ted Neward 介绍了 Scala 如何利用特征(trait)使对象更加简单、更易于构建。您将了解到,特征与 Java? 接口和 C++ 多重继承提供的传统极性既有相似之处,也有不同之处。
著名科学家、研究学者艾萨克。牛顿爵士有这样一句名言:“如果说我看得比别人远一些,那是因为我站在巨人的肩膀上”。作为一名热心的历史和政治学家,我想对这位伟人的名言略加修改:“如果说我看得比别人远一些,那是因为我站在历史的肩膀上”。而这句话又体现出另一位历史学家 George Santayana 的名言:“忘记历史必将重蹈覆辙”。换句话说,如果我们不能回顾历史,从过去的错误(包括我们自己过去的经验)中吸取教训,就没有机会做出改进。
您可能会疑惑,这样的哲学与 Scala 有什么关系?继承就是我们要讨论的内容之一。考虑这样一个事实,Java 语言的创建已经是近 20 年前的事情,当时是 “面向对象” 的全盛时期。它设计用于模仿当时的主流语言 C++,尝试将使用这种语言的开发人员吸引到 Java 平台上来。毫无疑问,在当时看来,这样的决策是明智而且必要的,但回顾一下,就会发现其中有些地方并不像创建者设想的那样有益。
例如,在二十年前,对于 Java 语言的创建者来说,反映 C++ 风格的私有继承和多重继承是必要的。自那之后,许多 Java 开发人开始为这些决策而后悔。在这一期的 Scala 指南中,我回顾了 Java 语言中多重继承和私有继承的历史。随后,您将看到 Scala 是怎样改写了历史,为所有人带来更大收益。
C++ 和 Java 语言中的继承
C++ 工作的人们能够回忆起,私有继承是从基类中获取行为的一种方法,不必显式地接受 IS-A 关系。将基类标记为 “私有” 允许派生类从该基类继承而来,而无需实际成为 一个基类。但对自身的私有继承是未得到广泛应用的特性之一。继承一个基类而无法将它向下或向上转换到基类的理念是不明智的。
另一方面,多重继承往往被视为面向对象编程的必备要素。在建模交通工具的层次结构时, SeaPlane 无疑需要继承 Boat(使用其 startEngine() 和 sail() 方法)以及 Plane(使用其 startEngine() 和 fly() 方法)。SeaPlane 既是 Boat,也是 Plane,难道不是吗?
无论如何,这是在 C++ 鼎盛时期的想法。在快速转向 Java 语言时,我们认为多重继承与私有继承一样存在缺陷。所有 Java 开发人员都会告诉您,SeaPlane 应该继承 Floatable 和 Flyable 接口(或许还包括 EnginePowered 接口或基类)。继承接口意味着能够实现该类需要的所有方法,而不会遇到 虚拟多重继承 的难题(遇到这种难题时,要弄清楚在调用 SeaPlane 的 startEngine() 方法时应调用哪个基类的 startEngine())。
遗憾的是,彻底放弃私有继承和多重继承会使我们在代码重用方面付出昂贵的代价。Java 开发人员可能会因从虚拟多重继承中解放出来而高兴,但代价是程序员往往要完成辛苦而易于出错的工作。
关于本系列
Ted Neward 将和您一起深入探讨 Scala 编程语言。在这个新的 developerWorks 系列 中,您将深入了解 Sacla,并在实践中看到 Scala 的语言功能。进行比较时,Scala 代码和 Java 代码将放在一起展示,但(您将发现)Scala 中的许多内容与您在 Java 编程中发现的任何内容都没有直接关联,而这正是 Scala 的魅力所在!如果用 Java 代码就能够实现的话,又何必再学习 Scala 呢?