|
原创:XuanTZ 2003年3月27日 <br> <br>首先指出,面向对象程序设计(OOP,Object-Oriented Programing)并不适合所有情况的编程。如果力求软件简洁、紧凑,面向过程仍然是最便捷的方法。然而面向对象技术本质上是一种思维方式,是不依赖程序设计语言的软件开发的基本核心技术,熟悉并运用这种方法实际是在掌握一种看问题的角度。所以不管是否专业人士,了解这种方法都是很有好处的。 <br>对象及类: <br><br><span style='color:blue'><span style='font-size:9pt;line-height:100%'>笔者并不建议初学者刚开始就急于学习OOP是如何用语言实现的,或者理解一些技术名词或源码,那样容易陷入一堆繁杂的规则而使本该清醒的头脑陷入混乱。学习面向对象技术应使读者建立一种科学的思维方式。当有了一套比较成熟的思考方法之后,你会很自然地以面向对象的角度考虑问题。即使是用C这样不支持面向对象语法的语言依然能设计出面向对象的解决方案,这些技巧例如用函数指针模拟类方法等笔者将会在以后的文章中详细介绍。 </span></span><br>类与对象的官方解释是:所谓对象,是一个属性(数据)集及其操作(行为函数)的封装体。类是对象的抽象及描述,是具有共同属性和操作的多个对象的相似特性的统一描述体。对象是类的实例。面对这些不易理解的话,看一些例子有点感性认识也许更好: <br><br>国家是一个类而中国是它的一个对象。<br><br> 在Windows中,窗口是一个类而浏览器窗口是它的一个实例。(对象) <br><br> 游戏中NPC是一个类,每个与你对话的人物都是它的对象。 <br><br> PhotoShop中画面是类,当前正在处理的画面是它的对象。(并不排除一个类在程序中只有一个对象) <br><br>相信你能举出更多的例子。你可以把类及对象当作仅仅是生活中的某种概念而不是OOP的专用名词。那么再来看看这些定义:属性是一系列描述该对象的数据,对于窗口,坐标位置、激活状态等变量都是它的属性;OOP并不排除过程,对象的行为实际就是对其属性进行操作的一组过程,例如窗口的最小化方法仅仅是改变了它的可见性,坐标值等属性。其实在面向过程的程序中,所有变量及常量都可归结为描述某个对象的数据,所有函数也可归结为某个对象发出的动作。对象不正是把散落的数据和函数作了归结么?至于类是什么,想想,你不可能单独为每个窗口编写最小化方法,你也需要一个东西描述所有玩家有那些属性是你关心的。类就像一个样板,它与对象的关系,就是工种与员工的关系。 <br><br> 如果将编程比成管理一家企业并完成指定项目,那么传统的面向过程的设计就像企业规模较小时,你注重的是作业任务;而OOP则是管理一家大企业,此时你比较注重的是员工。这里,员工就是你程序中使用的每一个对象。在尚未正式营业或需要作些变更时(设计类模板的阶段),你先要考虑需要那些种类的员工(类),像秘书、经理、清洁工等。以及他们有哪些工作(方法),有哪些特征需要关注(属性)。你在这个阶段制订了各个工种的样板。在设计工种时,你可能会规定经理有制订年度计划的工作,而不是规定张三有制订年度计划的工作。这个阶段,你是在规划所有你要雇用的这一类员工,每个你雇用的此工种的员工都将按照该规则去工作。在设计类模块的阶段,你不是针对个别对象的。而到了正式运营阶段,你也不会下达如经理去和网站签订合同之类的命令,你会说张三去和网站签合同。同样在类的设计完成之后,是通过具体的对象来调用某方法或访问某属性。你是用具体的员工运营整个公司的。 <br><br> 实际上面向对象的程序设计非常清晰地分为两个部分:构造类模块,以及用对象搭建你的程序。当然这两部分并非完全不可同步,往往是要穿插进行——当需要新的类时,就暂停搭建工作去构造所需的类模块。在比较大的工程里,完成搭建的程序员可以完全不知道类的内部是如何实现的。就好像在真正的经营阶段,你的工作(程序代码)可能看起来像这样:将张三调离人力资源部;李四去完成七月份市场调查;王五提升为项目经理等等。而对于张三本人(一个对象)来说,作为人力部的一名工作人员(“人力部员工”类的一个实例),它的调离工作(“调离”方法)就是:提取自己的档案,到会计处结算工资等,而这些具体的问题(该方法的具体实现)已不是你现阶段需要考虑的了。你在设计好模板后,就座上了一个老板的位置,下面的员工会处理好他们的任务和数据,你只需要发号施令。程序的修改只需要添加删除几个工种或调整他们的关系。类被构造出来后相当于给编程人员提供了一种现成的服务,程序员就像用户接受服务一样直接使用这些类模块,不管这些模块是自己先前构造的还是使用别人的。笔者经常在一些书籍中见到类似“类是封装的,只有其接口对用户是可见的”这样的话,这里面的“用户”就隐含着这种比喻。 <br><br> 笔者曾遇到很多初学者(也曾包括笔者本人在内)不理解为何要定义出这样一个“对象”的概念来,其实这更近乎于自然的思维方式,这对于从自然生活抽象成程序代码的编程过程来说,实际是很方便的。例如让一个外行人对一个游戏进行抽象描述(进而可以进行游戏设计),他可能看到:玩家有HP、经验值等属性,可以攻击(也就是具备“攻击”的行为方法),升级……如果再专业一些,也许会想到还有当前地图编号、是否完成某任务等状态属性,实际上这已经是在描述一个“玩家”类。读者有兴趣可以把这个类扩充的详细一些,例如攻击方法中可能有如下内容:如果打中,则敌人减血=玩加攻击力(属性)/敌人防御力(“敌人”类的属性)等等(顺便说一下,在速度为上的视频游戏中,尽量不要用除法这样慢的运算)。这在面向过程的程序里,这些过程都是分离的。按照这种思路,你可以建立所需的任何类,包括物品,地图等。在搭建阶段,你的工作就是生成一些NPC对象、玩家对象,写下如:若单击物品A,则玩家得到(方法)物品A。将这些翻译成代码,就能组成思路相当清晰的程序,不必项面向过程那样,在处理单击物品A时,将结构体“玩家”和“物品A”作为参数,传给一个通用的函数……你依然可以用面向过程的方法,将每个过程和数据组织得很规范,也可以设计出相当清澈的程序。你会发现,你组织的过程实际已经用到了面向对象的思路。 <br><br> 最后解释一下封装性。在前面的企业管理模型中,封装意味着员工的数据是自己保管的,只有自己的方法能修改或调用自己的(私有)数据,他人无权直接修改(尽管允许公有属性的存在,但在建模初期可以不考虑)。这样的好处在于对每项数据都做到了冤有头债有主,很少再有那些散乱的变量或常元。在支持OOP的语言中,这样也较好的解决了变量令人担惊受怕的作用域问题。一般来说,某对象需要修改其它对象的属性时,直接改变其属性的是被动对象的方法,主动对象只是调用这些方法。实际是很符合逻辑的,比如一个地球附近的质点,其属性就有:三个轴向的坐标、速度、加速度等,而它的可行的运动规律就有诸如:平抛运动、自由落体运动等,可以看成它的方法。其自由落体方法一般描述为:y(t)=-gt2/2。如你所看到的,是质点的运动改变了它的位置,而不是万有引力。也就是说,这里是该质点的方法改变了它自身的属性,而不是别的什么。引力只是调用了这个质点的落体运动方法,并未直接对其位置作修改。<br><br>不知你是否对类及对象有了初步的了解。由于笔者水平有限,文章中难免有疏漏的地方,恳请读者指出。 |
|