1. 程序是对数据区域的操作
一个典型的程序由两部分组成:数据+操作,程序指一定序列的操作。操作就是对数据进行变动。没有对数据变动的程序是没有意义的程序。对于数据,可以将其分解成为不同的区域。如下图所示:
上图中,ABCD为图中最小的数据区域,XYZ为次小级别的数据区域,T为包含所有数据区域的数据区域。一段程序,就是对这一系列的区域数据进行操作。
为了增加程序的独立性及安全性,往往会限定指定的代码只能访问特定的区域,为此而产生了多种不同的解决方案。所谓独立性,是指,只要把一小部分的数据区域及相关操作代码独立出来,放在任何一个地方都可以运行。安全性,指防止其它的代码访问到另外一个区域的数据。
2. C语言的数据区域
#include <stdio.h> #include "a.h" static int i = 3; int i_from_a() { return i; } int main() { int i = 2; printf("main: %d\na.c: %d\nb.c: %d\n", i, i_from_a(), i_from_b()); return 0; }
#include "a.h" static int i = 4; int i_from_b() { return i; } </file> <file c a.h> int i_from_a(); int i_from_b();
编译:
gcc a.c b.c
以上程序经过编译之后,输出如下结果:
main: 2 a.c: 3 b.c: 4
由图可以看到,i_from_a() 操作的数据 i ,是 a.c 里面的,i_from_b() 所操作的数据是 b.c 里面的,而 main() 中同样有一个 i。各自所操作的数据 i 是不一样的。
从上可以看出,c 语言通过静态变量与独立的 .c 文件来存放一个局部区域的数据。该局部区域的数据只能由同在一个 c 文件中的函数访问。
3. Java语言的数据区域
public class A { private int i; public A(int i) { this.i = i; } public int getI() { return i; } public static void main(String[] args) { int i = 4; A a = new A(i); System.out.println(i); } }
编译:
javac A.java
以上代码,运行输出以下结果:
4
由图看出,A 是一个模板,该模板定义一个数据区域 i ,并定义了对于该数据区域的一个程序 getI()。A(int i) 是构造 A 模板所定义的数据区域的程序。通过 new A(i) 可以产生一个实际的数据区域,并且产生对应于该数据区域的程序 getI()。
在 main 中,定义了一个数据区域 i,并且通过 new A(i) 定义了另外一个数据区域 a。其中 a 就是对应的 A 模板产生的一个实际的数据区域。可以使用 a.getI() 来取到 a 这个数据区域中的数据 i 的值。
4. JavaScript的数据区域
function a() { var abc = 0; return { inc: function() { return ++abc; }, dec: function() { return --abc; } }; } var b = a(); b.inc(); // 1 b.inc(); // 2 b.inc(); // 3 b.inc(); // 4 b.dec(); // 3 b.inc(); // 4 b.inc(); // 5
该段 javascript 代码的运行结果在上注释中作了标记。
由图可以看到,在 a() 中定义了一个数据区域 abc,该区域可以由 inc() 与 dec() 两个程序访问。a() 最后返回这两个程序组成的 javascript 对象,然后外界可以通过这两个程序来访问 a() 中数据区域 abc 的值。
5. 面向对象到面向过程
在以上三个例子中,c 语言被称为一个面向过程的语言,而 java 与 javascript 平常都被称为面向对象的语言。
通过 java 与 javascript 的比较,可以发现,两个语言都可以定义一个模板,然后根据这个模板构造出一个区域。通过区域的专用方法对区域数据进行访问。模板,实际上就是常说的类型定义。通过模板构造出来的实际区域,常被称为类型的一个实例。这种能够定义模板,并且能够构造出模板指定的区域数据及操作区域数据的程序的语言,称之为面向对象语言。
为什么会将面向对象语言这样定义?实际上,面向对象,就是模拟现实世界中的一类事物,将事物研究好,定义成一个模板。在需要一个事物的时候,就构造出该模板的一个实物。
举例,人类,有姓名,出生年月两个数据,并且可以有得到姓名及得到当前年龄的程序。从而,可以定义人类的模板,
人类 { 姓名 出生年月 报出姓名() 获得年龄() }
这样,在构造出的每一个人,都可以通过报出姓名()及获得年龄()来知道谁现在是多少岁。这样的方式符合人的思维习惯,从而很受欢迎,面向对象在地球上火了一把。
6. 问题与语言
了解了面向对象,在解决问题的时候,可以根据实际情况去考虑采用什么样的解决方案。并且,面向对象并非在所有的场合都是很好的解决方案。比如,在文本处理的时候,使用 perl 的正则表达式,就可以很高效地对文本进行处理,跟面向对象没有一毛钱关系。以下是一个统计某个 URL 地址访问量的程序:
open(F, "<data.txt"); while (<F>) { /^(\d+\.\d+\.\d+\.\d+) .*/; $count{$1}++; } close(F); foreach $key (keys %count) { printf "%15s %5d\n", $key, $count{$key}; }
要测试以上程序,可以在附后中找测试文件。
这样的问题,如果去面向对象,那将是一场噩梦。把一些本来就很简单的事情搞得复杂了。
所以,在解决问题的时候,要根据问题的现状考虑用什么语言。程序是用来模拟现实世界的,不同的语言有着不同的设计理念。从而为我们解决现实问题提供了很多可选择的基础。因而,了解不同的语言是有必要的。
附后
Perl 的测试文件
92.99.2.2 lfkdsjsdfkljds 10.3.44.3 94829483274327 92.99.2.2 lfkdsjsdfkljds 92.99.2.2 lfkdsjsdfkljds 92.99.2.2 lfkdsjsdfkljds 124.22.44.255 kfjdaslkfdjfads 10.3.44.3 94829483274327 92.99.2.2 lfkdsjsdfkljdslfkdjsfds 124.22.44.255 kfjdaslkfdjfads