hvs病毒:Java入门(2) 面向对象的程序设计

来源:百度文库 编辑:偶看新闻 时间:2024/05/09 07:04:14
Java入门(2) 面向对象的程序设计
摘要

  通过本章的学习,读者应对“面向对象”的程序设计有一个整体的认识,理解一些相关的术语,为学习Java语言编程打下基础。

(2002-08-29 14:07:43)

By Wing, 出处:fjxufeng

  本章目标:

  通过本章的学习,读者应对“面向对象”的程序设计有一个整体的认识,理解一些相关的术语,为学习Java语言编程打下基础。

  2.1 什么是面向对象的程序设计

  最早的程序设计工作,是直接使用机器码进行编程的,要利用计算机完成一件事,就得画上无数个0和1,编程不仅需要知识,还需要足够的耐心。第一代程序员们都是这样完成程序编写的,程序出错时,就不得不在众多的0与1之间寻寻觅觅,真的就象是在找虫子呀(Bug,表示错误)。这样的工作方法不仅需要花费大量的时间,还得付出不菲的金钱,不过这对于当时天价的计算机来说,是微不足道的。

  随着计算机应用的不断增多,软件开发任务也与日俱增。这时直接使用机器码来编程已经无法应付需要。这时汇编语言诞生了,它使用一些类似MOV、ADD、SUB等助记符来代替一长串0和1。我们先使用这样的语言写出源程序,再用汇编程序将它们翻译成为机器可以运行的机器码,这样使得软件开发变得更简单一些了。

  人类总是“发明工具”、“使用工具”、“完善工具”、“再使用”、“再完善”,循序渐进,不断地向前发展。使用汇编语言提高了软件开发的效率,但人类并未满足,又在汇编语言的基础上发展了更贴近人类语言的高级语言,如BASIC、Fortran、Cobol、C等。

  在高级语言出现时,计算机已经逐渐普通,正在以“摩尔定律”高速发展(计算速度越来越快,价钱越来越低),计算机的价格已不再是制约计算机应用的关键因素。人类需要大量的计算机软件来提高计算机的应用水平。而在这个时代,计算机硬件已经进入了有序、产业化的发展,但计算机软件却曾一度陷入失控的状态。如何让计算机软件更加可控制,可管理成为了一个十分重要的课题。

  小知识:

  在这个时代曾经暴发了一场“软件危机”,许多重要的软件项目都陷入失控的状态,如何使得软件项目胜利的完成,成为整个产业最为头痛的一个问题。曾经有一本著名的书籍《神秘的人月》将这描写成为:“失控的软件项目就象陷入泥潭的骆驼,越挣扎就陷得越深”。有兴趣的读者可以阅读一些相关的书籍。

  这一切“创就”了一门新的学科:《软件工程学》,将软件开发工作分成了“系统分析”、“设计”、“编程”、“测试”、“维护”等几个组成部分,一改以往“软件开发就是写程序”的认识。原来,软件开发工作就是充分发挥程序员的聪明才智解决问题,正如一句俗话所说的:“不管黑猫白猫,能逮着老鼠就是好猫”,在软件开发中,曾经奉行着一句矢志不渝的真理“只要能够解决问题的程序就是好程序”。这样,写出来的程序别说别人看不懂,有时连自己一段时间后都看不懂自己的程序了。试想,这样如何能够集众人力量共同完成一个软件项目呢,如何能够对一个软件项目提供有效的维护呢?

  通过了一段时间的摸索后,就形成了一套大家都很熟悉的面向过程的“结构化”软件方法学,包括结构化设计、结构化编程等软件开发方法学。如果大家在阅读这本书之前,有一些程序设计的经验的话,对这个应该还是有一些了解的。为了能够让大家理解“结构化”编程与我们在这里要说明的“面向对象”的程序设计的区别,在此我就用“伪代码”写一段程序(在本例中,我主要是用于讲解语法,而不考虑本程序是否有现实作用)。

  伪代码:

  伪代码,是指不能够直接编译运行的程序代码,它是用于语法结构讲解的一个工具,它比真正的程序代码更简明,更贴近自然语言。

  源程序:一个“结构化”程序示例:

  铅笔数=5

  钢笔数=6

  圆珠笔数=4

  其它笔数=7

……// 销售程序段铅笔数=铅笔数-1 // 卖出了1支铅笔其它笔数=其它笔数-2 // 卖出了2支其它笔// 采购程序段钢笔数=钢笔数+20 // 新进了20支钢笔圆珠笔数=圆珠笔数+10 // 新进了10支圆珠笔……

  正如上面的程序段所示,在结构化的程序我们通常是:

  1) 定义变量及其初始值;

  2) 根据事件发展顺序,进行相对应的处理。

  在上面的程序中,我们先定义了各种笔的初始总数,然后这些数量会在销售、采购时改变。这种程序的编写思路是随着事件,按照一定的过程来进行的。这种方法是一种“解题”的思维方式,把所有的需求,当作一个“应用题”一样来“解答”。

  可以看出,从机器语言、汇编语言到高级语言,程序设计越来越贴近人类的语言,但是它们又都有一个通病,就是它们都需要程序使用机器的思路,而不是人的思路,为什么这么说呢?那么人的思路是什么呢??

  人类认识世界的思路总是针对一个个具体的客观事物来认识,包括它的形状、大小等属性,以及行为、功能、动作等。就象一说到猫,就马上知道它是4只脚的、“喵喵”叫的,而且猫的行为动作大家也很熟悉,比如,我们说“猫抓老鼠”,大家应该马上就会在脑海中出现一个相应的图象吧。

  这时,人们突然发现,如果编写程序也采用这样的思维的话,那么将使得程序更加清晰,写起程序来也会变得更加简单了。软件工程学家便开始了坚持不懈的研究,终于创建了“面向对象”方法学,这一方法学的出现,使得软件工程又向前迈了一大步了。“面向对象”方法学其实包括:“面向对象的系统分析”、“面向对象的系统设计”、“面向对象的程序设计”……,而在本章中则主要探讨“面向对象的程序设计”。

  一些提示:

  熟悉Visaul Basic的读者,您应该记得在使用VB开发程序时,大家将一个个控件拖到界面上,然后修改它们的属性,使它们符合程序的需要,接着在这个控件的相应事件中填入代码。您想想,这不想我们儿时玩的搭积木吗,太简单了!这就是“面向对象”的程序设计给我们带来的好处呀。

  为了让大家对“面向对象”的程序设计有一些了解,我就再使用伪代码写一段代码,仅供大家比较。

  源程序:一个“面向对象”的程序示例

笔店{ 铅笔; 钢笔; 圆珠笔; 其它笔; 卖出(笔种类,数量) {笔种类=笔种类 - 数量; }进货(笔种类,数量){笔种类=笔种类 + 数量;}盘点(){打印 铅笔; // 打印出当前铅笔的库存量打印 钢笔; // 打印出当前钢笔的库存量打印 圆珠笔; // 打印出当前圆珠笔的库存量打印 其它笔; // 打印出当前其它笔的库存量 }}

  虽然,使用面向对象的程序设计方法好象更繁琐,但其逻辑结构严谨、有序,十分益于理解,而且,这里的“笔店”还可以在其它程序中使用,将大大提高开发效率。

  2.2 面向对象的主要术语

  传统的“面向过程”的方法学是把世界分成两个部分,分别认知:

  1) 数据(Data):用于描述各种状态的数据结构;

  2)过程(Procedures):就是操作这些状态数据的程序,有时也称为“算法”。

  说得形象一些,它认为数据是静态的,不会自行改变的,而需要各种各样的过程来改为数据。您还记得“数据结构”+“算法”=程序,这一个伟大的等式吗?这就是“面向过程”方法学的精髓。

  举个例子,我们要将一块木头从目前的位置向北搬到距原地10米的地方,我们首先会定义一个表示木头的数据结构,存储位置、质量等状态信息,然后再编写一个算法操作这个表示木头的数据结构,以达到目的。

  而“面向对象”的方法学则认为世界是由各种各样的对象(object)组成的,而每一个对象都有两个特征:状态(也称为属性)与行为(也称为方法)。

  说得形象一些,每个组成世界的对象都是通过自己的行为来变化自身的状态,一切变化都是对象自身、或对象间的协调而产生的。

  2.2.1 对象

  而上面那个例子如果使用“面向对象”的角度来看,我们会创建一个木头对象,这个对象不仅包括所有的属性、状态信息,还包括对它行为的描述。

  然后,我们让它执行一个自己的行为,使其发生相应的变化。这种方法更加符合自然世界,更加符合人类的思维习惯。

  也就是说,对象是一种对客观事物的抽象,它由状态(属性)和行为(方法)组成。

  下面,我们就使用一个图,来帮助大家认识对象。正如图2-1所示,我们使用一个大圆来表示一个对象,中间的一个小圆圈定义了这个对象的各种状态信息,外面则是各种各样的行为,通过执行这个对象的行为,就会改变这个对象的状态。

  图2-1 木头对象示意图

  2.2.2 类(Class)

  在真实世界中,通常有许多对象具有相同的性质。如你家的猫,只是世界上所有家猫中的一只;你家的电脑,只是世界上所有电脑中的一台……。这些猫、电脑……都具有类似的功能、相似的属性,但却又不是完成一样的。

  这在面向对象的概念里,把“猫”、“电脑”……等称为“类”,而“你家的猫”、“你家的电脑”则是这个类的一个具体的实例,一个对象。

  也就是说,类是一个集合,一个模板,通常我们在使用面向对象的程序设计中,我们是先定一个类,然后用类去定义一个对象,这个对象就可以使用了。

  还记得在2.1小节里,我们举的那个例子吗?我们首先定义了“笔店”这个类,它拥有4个属性:

  1) 铅笔;

  2) 钢笔;

  3) 圆珠笔;

  4) 其它笔

  同时还定义了三个行为:

  1)卖出:将属性的值减少,表示卖出;

  2)进货:将属性的值增加,表示进货;

  3)盘点:打印出属性的值;

  接着,我们在主函数中,先定义了一个属于“笔店”的对象:“张三笔店”,然后就可以对这个对象进行操作了。

  可以看出,类与对象的定义是一样的:状态(属性)+行为(方法)。因为类是对象的超集嘛。我们可以对类下一个定义:

  类是由所有相似对象的状态变量(属性变量)与行为(方法)所构成的模板或原型。

  2.2.3 封装性

  我们知道,对于一个对象来说,要改变自身的状态就意味着发生了行为。换一句话说,只有调用属于对象自己的行为才能改变自己的状态信息。

  在面向对象的程序设计语言中,您必须遵循这一原则,而且语言本身就提供了这样的机制,使得你不可能不遵循。这种机制称为“封装性”。

  从软件工程学的角度来看,这种封装性有效地将对象的状态数据隐藏起来,符合信息隐蔽原则,能够有效地避免因过失而破坏了状态数据。

  2.2.4 消息传递(Message)

  在前面,我们说到在面向对象的世界中,一切变化都是对象自身、或对象间的协调而产生的。那么它们是如何进行协商的呢?

  在面向对象的程序设计中,我们采用一种叫消息传递(Message Passing)的机制来实现。消息从一个对象发到另一个对象,使另一个对象完成某一个行为。

  通常,我们把发送消息的对象称为“发送对象”(sender),而把接受消息的对象称为“接受对象”(receiver)。其工作如下图所示:

  图2-2 消息传递机制工作示意图

  举一个我们身边的例子,在使用Windows 98时,我们可以在不同的对象上按鼠标右键,就会出现这个对象的属性菜单。例如,在桌面上按右键,就会出现桌面的属性菜单;如果在“网络邻居”图标上按右键的话,就会出现网络属性菜单……

  这就是通过消息传递来实现的,在Windows 98中,当我们单击鼠标右键时,“鼠标驱动程序”(一个对象)就会获取这个动作,然后向“系统”询问当前位置是什么对象,假设是“网络邻居”图标,那么它就向“网络邻居”这个图标(也是一个对象)发出一个消息,让其显示出属性菜单。

  Windows就是一个使用面向对象设计实现的,它采用了消息驱动机制,大家一定会记得,我们从开始菜单关机时,一些本来打开的程序在关机前先关闭,这都是消息机制的作用,在关机,系统向每一个运行着的“对象”传送了一个消息,使其关闭。

  2.2.5 继承

  在前面我们说过,对象是由类产生的,因此我们就可以通过对类的认识而了解对象。例如,假设你不知道“的士”是什么东西,我们只要说,“的士”是一种汽车,我想你马上就会知道个大概!而如果,我再进一步说明它是小轿车的话,你就会更明白了。

  到此,我们总结出一个道理,在现实世界中,有一些类比较大,可以分为许多小类,类是可以由其它的已知类来定义的。

  例如,汽车中有货车、客车、轿车……:

  1) 用于运输货物的汽车叫货车;

  2) 用于运输旅客的汽车叫客车;

  3) 豪华的、较低矮、较小的、有钱人(:-P)做的汽车叫轿车。

  而汽车、货车、客车、轿车都是类!在本例中,汽车这个类是货车、客车、轿车这三个类的超类(Superclass),而货车、客车、轿车这三个类则是汽车这个类的子类(subclass)。

  这四个类的关系,可以通过下面这个图来表示:

  图2-3 超类与子类

  如果定义了超类,那么子类就可以直接将超类中定义的状态、行为继承过来,不再需要另外定义了。因为这些属性子类也是具备的。

  而子类之所以成为子类,是因为它们相对于超类而言,还有一些不同的地方,这需要增加一些属性、行为。

  还用一些子类需要对继承过来的超类进行一些局部的修改,使其更能真实子类的特性。

  在现实世界中,继承是可以多重的,也就是说一个子类可以同时拥有多个超类。而毕竟程序设计的世界并一定要完全一样。在这个问题上,面向对象的研究者们有分歧,有一部分人认为应该采用单一的继承,而有另一部分人则认为应该采用多重继承。后来就在不同的面向对象的程序设计语言中体现出来了:

  1) 在C++语言中,支持多重继承;

  2) 在Java、Smalltalk、Objective-C都不支持多重继承。

  为什么要引入继承的概念呢?

  1)继承机制提高了“软件可复用性”。大家应该知道,在结构化的程序设计中,我们常常将一些经常要使用的功能模块写成子程序,供程序调用,这样会大大提高开发效率。这也就是“软件复用”。

  而通过继承,我们可以在已定义类的基础上无限地繁衍出更多的类,并且通过直接继承、新增、局部修改来重复使用超类。这样必将使软件开发的速度更快,同时可以使程序共享成为可能。

  共享代码:

  通过共享代码,我们就可以继承他人写的或系统提供的类,直接使用现成的程序码并可以加以改写,扩展成为我们需要的东西。例如在Java中,窗口类已由Java的开发工具提供了,因为我们要做一个窗口时就无须重写写过,只需直接使用就可以了。

  2)继承机制的另一个好处在于它使得接口更加一致。

  当超类衍生出许多的子类时,它的行为接口通过继承,也传给了所有的子类。这样,做消息传递时,就无需关心每个子类的接口,它们都是一致的。

  2.2.6 小结

  面向对象方法学博大、深奥,绝不是通过以上这些只言片语能够说得清楚的,在此只能是做一些简单的介绍,让大家对其有一个基本的了解,以便更好地学习Java语言。