7.1.1 面向过程观点
我们用一个简单程序来说明传统程序设计的思维方式。
【程序 7.1】eg7_1.py
x = 1
y = 2
z = x + y
print z
到目前为止,我们在编程时基本上都是这样思考的:先用特定数据类型的常量或变量来 表示数据(如程序 7.1 中分别存入变量 x 和 y 的整数类型值 1 和 2),然后再利用合适的操作(如程序 7.1 中的加法运算“+”)按一定的步骤来处理数据。在这种思考方式下,数据和对 数据的操作被看作是分离的两件事情:数据只是信息的表示,不表达任何操作,在程序中处 于“被动”地位;而对数据的操作在程序中则处于“主动”地位,是驱动程序实现特定功能 的力量。程序 7.1 可视为用操作“+”主动地去处理被动的数据 x 和 y,从而实现加法功能。 图 7.1 以一个比喻来形象地展示这种观点:数据与操作之间的关系正如心与箭的关系——没 有丘比特的箭,两颗心是不会彼此连结的。
图 7.1 传统观点:数据与操作分离
在数据与操作分离的传统观点下,通常以算法过程的设计为主线来展开程序设计,故可称为以过程为中心的程序设计。以求解一元二次方程的程序 3.6 为例,数据(系数 a、b、c) 明确后,需要精心设计的是处理这些数据的操作过程:先计算判别式 b2-4ac,然后根据判别 式的值判断方程是否有解,有解的情况下再利用公式求解,最后输出结果。
在以操作为中心的设计理念下,程序中的数据有时对整个操作过程都是公开的,可以被 操作过程中的每个步骤访问、处理。例如,假设程序 7.1 的操作不是单一的加法,而是在加法操作(第 3 行)之后还有两个操作:
w = x – y
z = z * w
可以看出,数据(x、y、z、w)对程序中所有的操作都是公开的。这时,程序中对数据的访问不受任何控制,非常容易出现错误的操作。
当然,实际的应用程序不会像程序 7.1 这样简单。复杂程序中不但数据复杂,而且对数 据的操作也非常复杂,所有操作可能形成漫长而曲折的过程。为了应付操作过程的复杂性, 按照第 4 章所介绍的模块化编程思想,可以将复杂操作过程组织成为若干个较小的模块—— 函数,每个函数实现一个相对简单的、单一的功能。例如下面这个“复杂”程序①:
【程序 7.2】eg7_2.py
def op1(a,b):
return a * a - b * b
def op2(a,b):
return a ** b + b ** a
x = 1
y = 2
z = 3
result1 = op1(x,y)
result2 = op2(x,z)
print result1 + result2
从一个更抽象的层次看,每个函数其实相当于一个操作。与程序 7.1 相比,程序 7.2 对 更多的数据(x、y、z)进行更复杂的操作:先执行 op1 操作,再执行 op2 操作,最后输出结 果。无论是程序 7.1 的简单操作“+”还是程序 7.2 的复杂操作“op1”、“op2”,它们都是“对 数据的操作”,仍然属于“数据与操作相互分离”的思考方式,整个程序仍然是对数据按一定 顺序执行操作的过程。
不过,作为高抽象级别操作的函数具有一定的访问控制能力。函数就像一个提供某种功 能的黑箱,使用者需要的只是它的功能,并不需要知晓它内部是如何实现功能的。函数内部 处理的数据不是对整个程序都公开的数据,一个函数不能访问另一个函数内部的数据。然而, 程序中仍然有一些全局数据是对所有操作(包括函数)公开的,仍然存在前述访问控制问题, 例如程序 7.2 中的两个函数 op1 和 op2 都在处理数据 x。
总之,不管程序是简单还是复杂,不管操作是语句级的还是函数级的,传统程序设计都 是按照数据与操作分离的观点,以过程为中心展开程序设计的。在这种面向过程的编程范型 中,强调的是对数据的操作过程,程序员思考的主要问题是数据如何表示、对各数据执行什 么操作以及各操作的先后顺序如何安排。当程序很复杂时,可以采用自顶向下设计和模块化 设计方法,将使用低级别操作的复杂过程设计成使用高级别操作的简单过程。
要指出的是,基于数据与操作分离观点的面向过程编程具有其内在的局限性,在处理某 些复杂问题和系统时显得不合适。例如,图形用户界面(GUI)程序②就不属于“对给定数据,
① 这个程序自然一点也不复杂,但不妨碍它可以用于说明复杂操作的问题。
② 详见第 8 章。
按特定次序对数据进行操作,操作完毕程序即告结束”的程序执行模式。以 Word 程序为例, 当启动 Word 打开文档(即程序数据)之后,接下去对数据如何操作呢?Word 程序并不知道 该做什么,它只能等在那里。接下去用户可能用键盘输入文本,也可能用鼠标点击菜单或工 具栏进行存盘或打印,总之用户需要通过某种交互事件来告诉 Word 程序该如何操作数据, 一个操作完成后 Word 又进入等待状态。可见,GUI 程序属于“先建立一个图形界面,然后 等待来自用户的不可预知的事件发生;事件发生后才导致执行某些操作,事件处理完毕又回 到等待状态”这样一种程序执行模式,程序从启动到结束的具体执行过程取决于事件发生的 顺序,不像传统程序那样预定义了执行顺序。
为了适应 GUI 程序这类没有明确的预定义操作次序、靠不确定的事件来驱动的程序和系 统的开发,提高开发效率和质量,计算机科学家提出了一种新的观点来看待数据与操作之间 的关系,即面向对象的观点。