[译]面向对象编程简史

原文链接:A Brief History of Object-Oriented Programming
原文作者:JIAN HUANG
翻译人:徐文志

面向对象编程简史

SIMULA是第一个对象语言,正如其名称所暗示的,它被用来创建模拟器。当时在犹他大学的艾伦凯对SIMULA语言非常感兴趣。他有一台将会提供面向图形的应用程序的个人电脑,他觉得像SIMULA语言将会为非专业人士创建这些应用程序提供便利。他将他的想法卖给了施乐公司(没错,就是那个给乔布斯灵感的公司)。上世纪70年代初,在施乐的艾伦凯领导的团队创建了一个名为Dynabook的的第一台个人电脑。 Smalltalk是专为做Dynabook开发的面向对象的语言,它是一个模拟和面向图形的编程语言。 Smalltalk虽然没有被广泛用于商业用途,但一直留存到今天。
面向对象编程的思想在20世纪70年代逐步流行,在80年代初期,Bjorn Stroustrup将面向对象编程集成到C语言,由此产生了C++,它成为第一个广泛商用的面向对象语言。

上世纪90年代初期,在Sun公司,詹姆斯·高斯林带领开发了C++的简化版本,即Java,Java本来为开发视频点播应用。该项目最终不温不火,直到这个小组重新定位Java,并把Java作为编程语言而销售。Java语言获得了蓬勃发展和广泛普及。

对象

提到面向对象编程必然要提到对象。最初的面向对象的语言被设计成适应真实世界的模型,因此在程序中的对象对应真实世界中的物体。
例如:

  • 对工厂车间的模拟 – 对象代表机器及原材料
  • 对行星系统的模拟 – 对象代表天体,如行星,恒星,小行星和气体云
  • 一台电脑的桌面 – 对象代表窗口,文档,程序和文件夹
  • 一个操作系统 – 对象代表的系统资源,例如CPU,内存,磁盘,磁带,鼠标和其它I/O设备

对于对象的想法是,它将存储一系列的数据,这一系列的数据将会存储一些操作,并允许操作数据。然而,这对用户隐藏了具体的实现。
真实世界的比喻,比如收音机,无线电的目的是广播电台的节目内容(实际上是将广播信号翻译为人能够理解的声音)。无线电有多种拨号允许你来控制不同的功能,比如你调整音量,音调,低音,电源等等。这些不同的拨号方式代表了你对收音机的操作。无线电的实现是不可见的。它可以用真空管或固态晶体管或一些其它技术来实现。问题的关键是,你不需要知道。电台实现从你隐藏的事实使无线电制造商升级电台的技术,而不需要重新学习如何使用一台收音机。

我们的想法是使用对象是相同的。一个对象表示了一组执行特定操作的方法集,但不对我们透露其执行情况。把它看成是一个黑盒。例如,想像一下在桌面上的所有对象。为简单起见,我们只关注两种类型的对象,文件对象和程序对象。文件对象包含数据和程序可执行语句。桌面需要来操纵这些对象。例如桌面需要能够复制,剪切,粘贴这些文档和程序对象。而桌面无需关心这些对象是如何实现这些功能的。它只是需要他们执行这三项功能。因此这文件对象和程序程序提供了能够被复制,剪切和粘贴的功能。

另一个例子,考虑一个栈。栈提供了一套如PUSH()、POP()、isEmpty()和TOP()操作。如果栈作为对象执行,其执行将从程序被隐藏。它可以实现为一个数组、一个队列或一些其它数据结构。该程序并不需要知道数组是如何实现的。其唯一关心的是,该栈提供指定的操作。

该组提供的操作被称为它的接口。该接口定义了操作的名称和行为。在本质上接口是对象和使用它的程序之间的契约。对象保证,它将提供一系列的操作集并且按指定的方式工作。

如果对象都由程序自定义也不会很好,对象也需要一个约束。例如,如果每一个收音机并不会非常普遍。我们需要一个办法,提供了一个对象的制作工序和用于“工厂”来对这道工序进行批量生产。类提供面向对象的编程这一机制。类是一个工厂,能够大量生产对象。程序员提供了类与对象所需类型的工序。 “工序”包括:

– 对象拥有的变量
– 对象拥有的方法

该组的每个对象具有变量被称为属性。该组的对象提供的操作被称为方法。一种方法就像是一种功能。
当一个程序需要一个对象的新实例,它要求相应的类来创建新的对象。类分配存储器来保存对象并返回给程序。每个对象都知道哪一个类创建它,以便当请求该对象的操作时可以查找在类实现该操作的方法,并且调用该方法。

继承

继承的动机在于,比如会有一款新产品叫收音机闹钟。收音机闹钟拥有所有的无线电功能来处理闹钟的功能。如果我们为收音机闹钟实现无线电的接口,即便不会操作收音机闹钟的人也知道如何操作它。因此,无需从头设计的收音机闹钟,我们可以扩展或继承由无线电定义的接口。当然,我们还可以使用无线电现有的实现和扩展它来处理闹钟功能。

在面向对象的程序设计,继承意味着另一个对象接口的继承以及也可能的重写功能的实现方式。它可以扩展接口,但它不能从接口删除任何操作。子类也继承了超类的实现,或者换句话说,实现了超类的操作功能。然而,子类可以自由地定义这些业务的新功能。这就是所谓的覆盖超类的实现。子类可以有选择性地挑选它覆盖其功能。未覆盖的任何功能都继承。

有一个很大的争论是关于如何使用继承。当你需要继承接口时,这种争论甚至已经达到是否应该使用继承的地步。例如,假设您要定义KV Store(键值对),并支持通过值来搜索对象时,搜索对象应支持以下操作:

– 插入:添加一个K-V对的对象。
– 删除:删除K-V对。
– 查找:给定一个K搜索V。

后来我们决定我们想要一个新的对象,允许我们遍历K-V对。新对象应该支持上述操作和两个额外的操作,即rewind()和next()。由于这个新对象支持所有的原始搜索对象的操作,我们可以使新的对象继承原始对象的接口。这是接口继承的一个例子。

执行模型

面向对象的一个原始设计目标是为了那些拥有多个操作对象的模型应用能够同时工作。
在操作系统中,各种输入装置,如磁盘、​​键盘和鼠标可以同时操作。在计算机游戏中,各种角色可能是人也可能是电脑,也可以同时操作。

这些应用程序都有一些共同点: 它们不是通过单线程控制的,而是将控制分发给应用,在任何给定的时刻多个对象或许想要执行一些操作。而传统的C语言就会在模型应用的处理上有麻烦,因为它是基于单线程控制的。而对象语言通过为每一个对象提供驻留空间解决了这样的问题,即多个对象可以在给定的时刻”同时”被执行(至少是一种概念模型, 一个顺序处理器的计算机可能是由交织的操作此模型)。对象之间通过传递消息相互通信。消息可能是调用另一个对象。例如,操作系统可能排队从各种输入装置处理到达的输入事件。每个输入设备可能被表示为一个对象,输入事件队列可能被表示为另一个对象。每一个输入装置接收到输入事件时,它会调用事件队列,向事件队列中增加了一个事件。

SmallTalk和Java是这种”一切皆为对象”概念的两个著名例子,他们也非常适合用来做分布式模型。而不幸的是,并非每一个应用程序都需要分布式模型,这正是这些面向对象语言遇到的问题。
Smalltalk和Java的是这两位著名的例子“一切都是对象”的概念。它们还非常适合用于建模分布式责任。不幸的是,并非每一个应用程序都需要具有分布式的责任,这正是这些面向对象语言遇到的问题。人们尝试这种模式强加给正在使用一个单独的控制线程更自然建模应用程序。发生这种情况时,程序员,程序员尤其是学习面向对象编程,感到困惑。

在这个过程中,我们将使用拥有不同的执行模式的C++语言。它保留了一个中央控制线程的概念。对象提供了控制的中央线的服务。例如,堆栈对象提供一个堆栈的服务。我们将主要使用对象来实现抽象数据类型。使用对象将会给我们带来的数据封装和代码重用的优点。数据封装意味着对象的执行被隐藏,因此,我们可以以不同的方式实现相同的接口。代码重用意味着我们可以在不同的应用程序中使用相同的对象,所以我们不必编写两次代码。

[译]面向对象编程简史

发表评论

电子邮件地址不会被公开。 必填项已用*标注