VB.Net中文教程(8) 对象(Object)基本概念
2024-07-10 13:02:43
供稿:网友
主题: 对象(object)基本概念
???????????? 内容 ????????????
v 1. 何谓「对象导向」?
v 2. 认识与寻找对象
v 3. 对象之分类与组织
v 4. 类别之设计
v 5. 对象之行为
v 6. 讯息与运算
v 7. 类别之定义
v 8. 着手写 vb程序
大地运转、花开花谢、及枫叶飘零 ...... 是自然界对象之行为。对象行为交互作用﹐造成多采多姿的大自然。软件的对象是自然界对象的抽象表示,软件就逼真地表达自然界的实际景象﹐于是人们心中构思的软件和眼中所见到的世界是一致的。软件是自然界实况的抽象﹗简单明了﹐能帮助人们了解和掌握真实景物。本文介绍vb的对象观念,让您轻易以vb描述身边美丽多变的世界。 ----- 摘自 高焕堂 的文章
1. 何谓「对象导向」﹖
在企业上常有「行销导向」及「技术导向」之名词﹐行销导向讲得更通俗一点就是行销挂帅﹐亦即行销观念为整个企业营运计划之核心。而技术挂帅就是以技术创新为公司活动之核心。同样地﹐在软件开发方面﹐传统 c语言之核心观念是「函数」(function)﹐进而让函数之间可互相呼叫并传递数据。在 cobol程序中﹐大部分的程序设计工作摆在 cobol程序的程序部(procedure division)中﹐进而让段(paragraph) 之间互相呼叫(perform) 。当您看到 c程序时﹐脑海里充满着函数的影子﹔当您想到 cobol程序时﹐心理也充满段、节等观念﹐就像我们想到或看到万里长城时﹐马上联想到它是由许多石块所构成一般。因之﹐传统的程序设计是「函数导向」(function-oriented) 或称为「程序导向」(procedure-oriented)﹐着重于计算机处理资料时的执行过程。
后来﹐资料导向观念出现了﹐资料在经过程序的处理后会有所改变﹐这转变的途径﹐成为软件设计过程中﹐注意力的集中点﹐这称为「数据导向」(data-oriented) 。
现在的「对象导向」(object-oriented) 观念﹐在软件开发时﹐甚至写程序时﹐对象(object)成为脑海里的主角。当您看到程序时﹐心理充满着对象之影子和概念﹐函数和资料变成对象内之一部分﹐是配角而非主角了。程序设计之核心工作在于描述对象、组织对象、安排对象间之沟通(传递讯息)方式。就如同「人」是社会中的主要对象﹐社会是有组织的人群﹐人们之间会互相沟通、协调。
由于软件中的对象观念和实际社会中的对象观念是一致的﹐所以 oop观念使软件与实际世界间之距离缩短了。此为 oop技术的重要特点之一。例如﹕函数或程序导向之核心观念──函数﹐在一般人们的心目中﹐并非熟悉之概念﹐只在数学里学到之概念而已。因而让人对软件感到陌生。而在对象导向观念中﹐实际社会之对象﹐例如﹕人、汽车、股票、磁盘驱动器、帐单、房间、学生、教室等皆为软件设计师脑海中的对象﹐也是程序中的对象。因之﹐不论是老板或程序设计师来看程序﹐他们脑海中皆充满对象之影子﹐而这些个体皆为人们生活中﹐真正活生生的东西、实在之物体或大家耳熟能详之概念﹐使得软件之使用者和设计者有一致的心灵、共同之感觉﹐这让使用者对软件更满意﹐设计师更了解使用者之需要。
2. 认识与寻找对象
着手设计一个系统或写一个程序时﹐第一件会出现在脑海中的问题是﹕对象那么多﹐何者是跟此系统或程序有关的呢﹖例如﹕在设计一个销售系统时﹐「顾客」是一重要对象﹐产品及订单也是重要对象﹔至于原料之产地及原料之供货商虽然是明显的对象﹐但不见得与销售系统有关。反之﹐若您所设计的是采购或生产系统时﹐原料、产地及其供货商就跃然成为重要对象了。在寻找对象之过程中也会让您对所要设计的系统有更清楚之认识。
现在就来介绍较实用之找对象方法。其中最常见的是﹐从有关文件着手。在文件里会发现下述线索﹐再进而找出对象。
(1) 人(people)──人是任何系统之重要角色﹐通常是最容易找到之对象。例如﹕公司有 5位销售员﹐各负责一个地区的任务﹐并与该区的顾客连络。从这段叙述中﹐就可发现两种对象──销售员及顾客﹐每一位销售员皆是对象﹔同样地﹐每一个顾客皆是对象。
(2) 地方(sites) ──地点是很容易发现之对象。例如﹕您从订单上看到产品将送达之目的地、顾客之所在地。再拿旅行社行程来当例子﹐各旅行团将于不同之观光地区停留﹐各观光地点皆是对象。
(3) 事物(things)──在可摸到或看到的实物中﹐也容易找到与系统有关之对象﹐例如﹕产品是销售系统及生产系统之明显对象﹐原料项目是生产及库存系统之重要对象。就旅馆管理系统而言﹐「房间」是重要对象。「书本」及「杂志」为图书馆或书店管理系统之明显对象。
(4) 事件(events)──在企业界最常见之事件是「交易」﹐当事件发生时﹐我们会去记录它发生的时刻、有关金额等等。这种我们所关心的事件也常是重要之对象。值得注意的是﹐这些事件是已发生的﹐其为一项行为或动作。所以在文件中﹐常是一个句子的动词。例如﹕今天共有 3种原料已降至安全存量之下﹐所以共订购 3种原料。这每一「订购」(ordering)事件皆是对象。就飞机场的控制系统而言﹐每次飞机「起飞」或「降落」 皆是重要对象。而「提款」及「转帐」皆为银行系统之重要对象。「挂号」及「就诊」为医疗系统之对象。
(5) 概念(concepts)──与企业营运或机构管理有关之「构想」或各种「计划」或其它观念﹔这些无形的﹐但决定企业活动之构想﹐常是重要对象。例如﹕公司正拟定三种广告策略﹐其中每一策略就是企业行销系统之重要对象。这公司正透过 2种管道与社区居民沟通﹐这管道也是概念性之对象。
(6) 外部系统或设备(external systems or devices) ── 软件系统常会与其它系统沟通﹐互相交换信息。有时也由外部设备取得交易资料或把处理结果送往外部设备。这些外部系统或设备也是对象。例如﹕库存系统与采购系统会互相沟通﹐对库存系统而言﹐采购系统是对象﹔反之﹐对采购系统而言﹐库存系统则为对象。如果收款机直接把交易资料传送给销售系统﹐则收款机是此销售系统之对象。如果股票系统直接把资料传送到交易市场的电视显示屏上﹐则对股票系统而言﹐电视显示屏是对象。
(7) 组织单位(organization units)──企业机构之部门或单位。例如﹕在学校管理系统中﹐教务处及训导处等单位皆是对象。
(8) 结构(structures)──有些对象会包含其它对象。所以在对象中常能找到其它对象。例如﹕在学校的组织单位──教务处﹐含有小对象如注册组及学籍股等。在汽车对象中可找到引擎、轮胎及座椅等对象。在「房屋」对象中﹐会发现到厨房、客厅、沙发等对象。
以上介绍的是常用之寻找对象方法﹐会寻找对象之后﹐就必需将对象分门别类﹐并且了解类别间之关系﹐以便把它们组织起来。例如﹐在公司的人事结构中﹐可发现人因扮演角色之不同而分为不同种类之对象﹐如推销员、司机、经理等等。汽车可分为跑车、巴士、旅行车等不同种类之对象。如何分类(classification)﹐是oop 之重要观念。
3. 对象之分类与组织
3.1 类别的永恒性
俗语说﹕物与类聚。「物」和「类」说明对象与其所属「类别」(class) 之关系﹐相似之对象常归为一类。例如﹕一个人是对象﹐人类是由个人所构成之类别。「狗」这种动物是类别﹐我家那只哈巴狗是对象。当您获知公司有 a、b 两位推销员时﹐可得知 a、b 两者皆为对象﹔同时﹐也联想到「推销员」(salesman)是类别﹐而 a、b 皆是此类别内之对象。
由于类别比对象较具有永恒性﹐在设计软件的过程中﹐当您找到对象时﹐也必须掌握此对象之类别﹐如此软件自然会更具有永恒性﹐亦即软件的寿命会更长。例如﹐一个人从出生到老﹐不超过二百年﹐而「人类」则因对象生生不息而永远昌隆。在学校里﹐king老师会换工作而离开学校﹐但「老师」类别将永远存在。因之﹐个体及其所属的群体──类别﹐皆是 oop之核心观念。善于利用类别把对象归类﹐并且组织起来﹐是对象导向软件开发的重要技术。在设计软件时﹐通常必须先决定有关的类别﹐并且弄清楚类别之间的关系。兹介绍两种最常见之类别关系﹕「父子关系」和「整体╱部分关系」。
3.2 父子类别关系
人们从小就学习对东西分类﹐将东西分为「生物」及「无生物」﹐其中生物又分为「动物」及「植物」等。无论动物、植物或生物皆为类别(class) 。动物是一种(a kind of) 生物﹐植物也是一种生物。此时﹐即称动物是生物的子类别(subclass)﹐植物也是生物的子类别﹐而生物是动物及植物的父类别(superclass)。这种父子类别关系是软件中的组织相关对象的重要方法。例如﹕汽车、马车、脚踏车皆为一种车﹔所以﹐车是父类别﹐而汽车、马车及脚踏车皆为车之子类别。
设计软件时﹐当您知道公司今天生产 5部巴士及 5部轿车时﹐您已找到10个对象了﹐其中每一部车皆为对象。它们分别属于不同类别──巴士及轿车﹔然而﹐因巴士及轿车皆为一种(a kind of)汽车﹐所以轻易地找到其更大的类别──汽车。利用父类别──汽车把两个子类别──巴士及轿车组织起来﹐其关系可表示如下:
图1 父子关系
于是﹐在我们所设计的软件中﹐将包含这三种类别。
日常生活中﹐父子关系是很常见的类别关系﹔经由这种关系﹐也很容易决定与软件有关的类别。例如﹕一家公司正在生产 3种鞋子──网球鞋、篮球鞋及慢跑鞋。此时我们已找到了 3种类别──网球鞋、篮球鞋及慢跑鞋。由于网球鞋及篮球鞋皆为一种球鞋﹔所以﹐进而找到父类别──球鞋。球鞋及慢跑鞋皆为一种鞋子﹐所以又找到了它们的父类别──鞋子。因之﹐得到关系如下﹕
图 2 多层父子关系
如果为这家公司设计软件﹐这 5种类别是软件中的重要类别﹐同时这种父子类别关系﹐正是软件用来组织有关对象(各双鞋子)的好方法。由于软件设计者的脑海中﹐对象的组织方法和一般管理者脑海中的分类方法是一致的﹐这能使软件更适切地满足使用者的需要﹐也提高了软件的价值。
3.3 整体╱部分关系
上节谈过﹕对象常包含其它对象﹐从对象之结构(structure) 能找到其它对象。例如﹕一部汽车含一个引擎及 4个轮胎。
图3 对象之整体╱部分关系
从这对象结构﹐发现到两类别──引擎及轮胎。其类别关系为﹕
图4 类别之整体╱部分关系
引擎是汽车的一部分(a part of) ﹐轮胎是汽车的一部分﹐所以汽车是「整体」(whole) ﹐而引擎及轮胎是「部分」(part)。
在实际的产品结构中﹐常见整体╱部分关系。例如﹕灯泡含灯心、灯帽及玻璃球﹔书本含封面、目录及内容等部分﹔计算机系统含屏幕、键盘、主存储器及磁盘驱动器等等。在软件设计时﹐也常依照这结构来组织类别及对象。例如﹕在程序中﹐就可定义汽车、引擎及轮胎三种类别。
请注意﹕上述关系﹐其整体与部分间有共生共灭之密切关系。例如﹕一个灯泡破了或者烧坏了﹐通常整个灯泡﹐包括其内部的灯帽、灯心、玻璃球一齐都被丢弃了。于是﹐在软件系统中﹐这些部分对象(如灯心)皆会随着整体对象(灯泡)之消失而一起消失了。反之﹐司机对汽车而言是不可或缺的﹐但没有人认为司机是汽车的组件﹐原因是一部汽车报销了﹐司机可还存在呢﹗然而﹐司机仍是汽车的一部分﹐因为在空间上﹐汽车对象中﹐仍包含了司机对象。因之﹐汽车与司机之间仍是整体╱部分关系。
这种关系也很常见﹔例如﹕笔心是自动铅笔的一部分﹐但笔心并不与铅笔共生共灭。同样地﹐干电池是手电筒的一部分﹐但两种对象并非共生共灭。这种整个╱部分的关系﹐也让我们很容易找出相关的对象和类别﹐同时也能利用这种关系来把软件中的对象组织起来。
上述两种关系是实体物之间的整体╱部分关系。然而在概念性的对象或类别之间也常见整体╱部分关系﹔这些经常是企业活动或计划之概念性对象。例如﹕在旅行社中﹐旅行团的行程常分为数段﹐每一段行程是总行程的一部分。
由于企业营运计划常为企业管理的核心工作﹐而计划或活动经常由数个更小的计划或活动所构成。所以在 oop技术中﹐常用整体╱部分关系来表示这种概念性类别之关系。
再从企业机构的组织来看﹐一个组织(organization)经常有其成员(member)﹐这组织与成员之间也是整体╱部分关系。例如﹕一个公司分为数个部门﹐每一部门又数个职员﹐则部门是一组织﹐而职员是该组织的成员﹔亦即﹐部门与职员是整体╱部分关系。
由于公司包含数个部门﹐所以公司与部门之间也是整体╱部分关系。此外﹐职员也是公司的成员﹐所以公司与职员之间也是整体╱部分关系。
由于组织与成员之间关系是府拾可得之整体╱部分关系﹐极为常见﹔因之﹐经由这种关系可找到有关之对象及类别。在设计软件时﹐可别忘了掌握此重要关系。事实上﹐软件也应表达出这种关系﹐才能使得软件中的对象结构与实物世界中的对象结构一致。
在对象导向程序设计之过程中﹐通常先于程序中定义有关之类别﹐再利用已定义之类别来诞生对象来与实物世界中的对象相对应﹐以便让软件更贴切地表示实际的系统之需求。因之﹐在找到对象之后(其方法如上节所述)﹐就确定它们的所属类别。确定了这些基本的类别之后﹐就经由「父子关系」找出有关的父类别或子类别﹐并且确定这些类别之间的关系。再接下来﹐就是利用对象之间的整体╱部分关系﹐来找出相关的对象﹐并进而找出相关之类别﹐并且确定这些类别之间的关系。
本书里﹐将以 vb.net语言来说明如何运用类别来组织对象﹐并像建造万里长城般有系统地将对象组织起来﹐形成既可靠又好用的现代软件。
4. 类别之设计
对象导向程序设计(object-oriented programming 简称 oop)之观念能大量简化计算机软件之复杂度﹐让人们更容易发展及维护软件。oop 的两个最基本观念是﹕类别(class) 及对象(object)。俗语常说﹕「见树不见林」或「见林不见树」﹐其中的林就是「类别」﹐而林之组成元素──树就是「对象」了。依传统之程序写法﹐主要之程序设计工作是在于设计指令、叙述及函数等等﹔然而在oop 之新观念中﹐写程序的主要工作在于──设计类别﹐亦即「造林」之工作。设计各式各样之类别后﹐再做「雕材」的工作﹐对树木做各种运用﹔亦即﹐使用类别之对象﹐而产生有价值之信息。请看如何设计一类别叫──tree(树林)﹐其格式为﹕
class tree
品种
年龄
高度
end class
此告诉计算机﹕对于树林中的树﹐将记录其 3种特性(attribute) ──品
种、年龄及高度。例如有一棵树﹐其特性为﹕
品种﹕peach
年龄﹕8 年
高度﹕2.1 尺
这是树林中的一棵树﹐在计算机的tree类别中﹐就必须有一「对象」(object)和它对应并且储存它的特性。至于如何产生tree类别之个体呢﹖其指令为﹕
dim x as new tree()
此时计算机就诞生对象 x。x 能储存此树之资料如下﹕
如果您想记录别棵树之资料﹐可再宣告tree类别之对象如下﹕
dim y as new tree()
对象 y就可储存此树的资料了。实物上之关系﹕
树林 <----> 树
树林是一个集合(set),一棵树是集合里的元素。其表现于计算机程序上是﹕
类别 <----> 对象
类别是一个集合,一个对象是集合里的元素。
此为 oop之基本观念。类别设计之优劣常决定软件之生命和价值﹐好的设计其软件寿命源源流长﹐价值连城。类别之设计并非到此为止﹐还要继续做一项重要工作──分类(classification)﹐亦即寻找「子类别」(subclass)。例如﹕上述树林中的树若可分为两种──果树与竹子﹐则「树林」类别可分为两个子类别──「果树」与「竹子」。
图5 类别之细分(refine)
此为实物上之类别关系。程序中的类别关系必须和实物上的情况相呼应。程序中的类别宣告格式为﹕
class tree
品种
年龄
高度
end class
class fruittree
inherits tree
成熟月份
价格
end class
class bamboo
inherits tree
用途
end class
其中﹐fruitttree及bamboo是tree之子类别(subclass)﹔而tree是fruittree及bamboo之父类别 (super class)。于程序中﹐其关系表示如下──
class 类别
inherits 父类别
fruittree类别中含有两项新特性──「成熟月份」及「价格」。这告诉计算机说﹕对于果树﹐必须多储存两项资料。这两项资料是果树才有的﹐竹子就没有。bamboo类别中含有一项新特性﹐这告诉计算机说﹕对于竹子﹐必须多储存一项资料──「用途」。这是竹子才有的资料﹐果树则无。例如﹕有一棵果树﹐其资料为﹕
品种﹕peach
年龄﹕8 年
高度﹕2.1 公尺
成熟月份﹕3 月
价格﹕20 元
在计算机中﹐必须宣告fruittree类别之对象来储存这些资料。欲产生此对象﹐程序可写为﹕
dim a as new fruittree()
此时计算机就产生一个fruittree类别之对象﹐叫 a。它包含5项资料──
其中包含了tree类别内之 3项资料以及fruittree类别专有之两项资料。因为tree为fruittree之父类别﹐所以fruittree「继承」(inherit) 其父类别tree的 3个特性。
图 6 资料的继承
同理﹐如果有一棵竹子﹐其资料为﹕
品种﹕green
年龄﹕2 年
高度﹕10.0 公尺
用途﹕chopsticks
在计算机中﹐必须宣告bamboo类别的对象来储存这些资料。欲产生此对象﹐程序可写为﹕ dim b as new bamboo()
此时﹐计算机就诞生一个bamboo类别之对象 b。它可储存 4项资料──
其继承(inherit) 了tree类别之 3个特性。
图7 资料的继承
父类别tree内之资料为子类别── fruittree 和bamboo都具有之共同特性。此为oop 类别设计之基本原则。
5. 对象之行为
树林中的树会长高或变矮(遇台风等)﹐计算机中储存这些资料之对象必须随之改变﹐即对象内之资料会改变。果树的果实售价改变了﹐fruit_tree类别之对象也须改变﹔这种对象内资料之变化是对象(object)之「行为」(behavior)。对象之基本行为包括﹕
(1)把资料送入对象并储存起来。
(2)改变对象内之资料。
(3)拿对象资料来做运算。
(4)从对象中送出资料。
例如﹕30公斤peach之总金额为何﹖此时﹐可拿对象a内之价格资料来做运算──
我们的目的是要拿对象 a中的价格资料(20元)和重量(30公斤)相乘﹐进而算出其总金额(600 元)。然而在oop 的观念中﹐则必须将其解释为──「把 30 送进对象 a﹐在对象内部做相乘运算﹐然后把总金额 600送出来。」 其中﹐ 600是对象 a接受到外界的「讯息」(message) 之后﹐才做出的反应﹐至于它的反应过程(乘法运算)则是在对象 a内部完成的。就如同一个电灯泡﹐当电流进入灯泡中﹐此灯泡会发出亮光。这是人们日常府拾可得之经验﹐如果计算机软件像灯泡一样一点就亮﹐不知可多得若干人的芳心呢﹗当你到台北火车站买车票时﹐只需把钱投入售票机中﹐经过一些处理之后﹐就有反应﹕把车票吐出来。
上述之实物对象(如自动售票机)接到讯息(message) 时﹐其内部产生运作﹐并输出运作之结果。同样地﹐程序内之对象(object)接到讯息时﹐其内部也对资料做运算﹐并输出运算结果。例如﹐想知道 peach树之高度为何﹖可将此讯息送进对象 a中﹐它会输出此树之高度。
对象对讯息会产生反应﹐但并非对任何讯息都有反应。例如﹕灯泡只会对电流有所反应──发光。自动售票机必须投入钱才会有反应──送出票来。如同一只猫﹐它对一个身边的馒头可能不会有反应﹐但对身旁的老鼠将会出现强烈之反应。
当我们使用灯泡或自动售票机时﹐能轻易学会其使用方法──知道输入什么讯息﹐也很清楚它们的反应。类似地﹐在oop 程序中﹐你也能轻易学会对象(object)的使用方法──知道输入什么讯息﹐及了解其反应。所以﹐使用程序内之对象﹐就像使用灯泡一样的简单方便。
换个角度来说﹐如果您是自动售票机之设计人﹐就须负责设计机内之处理过程(反应过程)﹐并使输入讯息更简单﹐而反应更清楚。同理﹐如果您是对象之设计师﹐就得负责设计对象内之运算过程(对讯息的反应过程)﹐并使输入讯息更简单﹐而反应更清楚。
6. 讯息与运算
如果您是手表之设计人﹐则需把电池放入手表中以提供电力。此时﹐您既使用现成之对象──电池﹐也创造新对象──手表。同样的情况﹐写计算机程序时﹐您经常是对象之使用人﹐亦为对象之设计人。因之﹐利用既有而完美之对象去创造更有用之对象﹐乃为oop 程序员的天职。设计手表时﹐您心理必定很清楚这新手表会有何功能﹐譬如﹕如何设定时间、表示时间(指针或数字)等等。也就是说﹐您一定对这手表将呈现之「行为」(behavior)有很清晰之构想。其行为包括﹕
(1) 它接受何种「讯息」(message) ﹖例如﹕按键输入时间。
(2) 对讯息将会有何反应﹖例如﹕显示时间或日期等。
在我们周遭之实物世界中﹐各物体都有其固定之行为﹐所以我们能轻易掌握它﹐且觉得可爱。例如抽烟者常携带的打火机﹐只当用力按它时才有火苗出现﹔一颗手榴弹也在某种动作下﹐才会引爆﹐否则您一定不敢用打火机﹐面对敌人时也不敢用手榴弹。
设计程序中的对象时﹐也得设计它的「行为」﹐决定它将接受何种讯息﹐并且对讯息会产生何种反应。然因您是设计人﹐所以有项必须担任之工作──设计对象内部之运作﹐使它对讯息产生正确的反应。就像您组织手表内部之零件、打火机内部之结构以及手榴弹内部之引爆过程等等。这就是对象设计者之主要工作﹐其目的是﹕让别人有个好用而易于掌握之对象﹗
以前设计vb程序时﹐在我们心中ㄉ主角是「函数」(function)或「子程序」(subroutine)。现在就得把函数摆入对象中﹐让对象有所行为──对讯息有所反应。当您对所设计之对象的行为有清晰的构想之后﹐就自然知道应将那些函数置于对象中。就如同设计手表者依手表的功能决定应有那些零件一般。您去购买现成的零件、创造零件、选择适当的电池﹔接下来就将这些零件组织于手表内。写程序时﹐您使用既有之函数(例如﹕vb 已提供之函数)、创造新函数、也利用既有之对象﹔接下来就将这些函数和对象组织于新对象之中。
至于应如何组织这些函数﹖如何运用现成之对象﹖即为本书之主题了。现在请回到tree类别之例吧﹗上节里﹐已经诞生对象 a如下﹕
接下来﹐可设计一个函数叫computeamount(weight)﹐它能求算总金额。如果把这函数加入对象a 中﹐那么对象a 就有如下反应──
如果另设计个函数叫 inquireheight() ﹐并将之加入对象 a中﹐则对象 a就能输出树之高度﹕
这如同设计灯泡者将钨丝及稀有气体放入其中﹐灯泡才会发光。至于灯泡之使用人就不必为灯泡内部的东西及运作过程而伤脑筋了﹔因之﹐人们会喜欢使用灯泡。灯泡把材料和反应之过程「封藏」(encapsulate) 于灯泡内﹐您只需把电流(讯息)传入灯泡(对象)中﹐它就发出亮光(反应)。
写程序时﹐您把函数摆入对象中﹐对对象内之资料做运算﹐并且输出结果﹐此时函数内之指令担任这项运算工作。由于函数存于对象内﹐而资料之运算进行于函数内﹔所以﹐运算的过程(亦即反应的过程)就被「封藏」于对象之内。对象之使用人不必为这些函数之运算而伤脑筋﹐也就觉得对象是简单好用。如果计算机软件是由对象组织而成﹐人们就会觉得软件是既简单又好用。就像灯泡可装在车子上﹐也可装在房子内﹐裨构成更大之对象(车子、房子都是对象)。此程序设计观念﹐就称为「对象导向程序设计」。
假设您已把computeamount(weight)及inquireheight()两个函数加入对象 a中﹐就可把讯息送给对象a ﹐指令可写为﹕
a.computeamount( 30 )
这意思是﹕把讯息──computeamount(30)送给对象 a。此时对象a 内部之computeamount()函数就会进行运算(把 30 和 20 乘起来)﹐并且送出总金额 600元。您可输入另一讯息﹐指令为﹕
此时﹐对象 a内之inquireheight()函数就会进行运算(读取高度── 2.1)并且送出该树之高度﹐亦即 2.1公尺。看看较完整的vb程序吧﹗
protedted sub form1_click( .... )
dim amount as double
dim height as double
dim a as new fruittree( "peach", 8, 2.1, 3, 20 )
amount = a.computeamount( 25 )
height = a.inquireheight()
messagebox.show("amount= " + str(amount) + "height= " + str(height))
end sub
此程序中﹐对象 a首先接到一讯息──computeamount(25)﹐对象a 就会激活其内部的computeamount()函数﹐此函数就拿25和对象中的价格20相乘﹔函数计算完毕得到 500﹔对象 a就将其送出来。
计算机再将 500存入amount变量之中﹐则amount之值是 500。接下来﹐对象 a又接到另一讯息──inquire_height()﹐对象 a激活其内部的inquire_height()函数﹐此函数就读取对象内的「高度」──2.1 ﹔且把 2.1送出来。
计算机将 2.1存入height变量之中﹐则height之值为 2.1。最后﹐计算机把amount及height变量之值显示于屏幕上──
amount = 500 height = 2.1
7. 类别之定义
一只猫是对象(object)﹐不同的猫其大小、颜色各不相同﹐但是它们有很多相同之行为﹐您才认为它们是猫﹐也才将它们归于同一类﹔譬如喜欢捉老鼠、善于爬树、怕水等等。因之归于同类别之对象具有共同的行为(behavior)﹐亦即各对象对讯息(message) 之反应过程是相同的﹐这反应过程可由同一函数担任。例如﹐下述指令产生 a及 k两对象──
dim a as new fruittree("peach", 8, 2.1, 3, 20)
dim k as new fruittree("pineapple", 2, 0.5, 6, 10)
假设其内部资料为﹕
因 a及 k是同类别之对象﹐所以对同一种讯息的反应过程是一样的﹔但由于对象内部的资料并不相同﹐其反应的结果有所不同。
对于讯息──computeamount(25)而言﹐对象 a会激活computeamount()函数处理它﹔而对象 k也激活computeamount()处理它﹐其处理过程是相同的。也就是说﹐对象 a和 k共享computeamount()函数来处理这讯息。此computeamount函数可写成﹕
function computeamount(重量)
computeamount = 重量 * 价格
end function
于是﹐把这函数加入fruittree类别中──
class tree
品种
年龄
高度
end class
class fruittree
inheits tree
成熟月份
价格
function computeamount(重量)
computeamount = 重量 * 价格
end function
end class
class bamboo
inherits tree
用途
end class
如此﹐fruittree类别之各对象都对computeamount(25)讯息有所反应﹔各对象皆使用这computeamount()函数来处理此讯息。您可认为各对象共享computeamount()函数﹐也能认为每对象内皆有一份computeamount()函数﹐以便处理这种讯息。接下来﹐继续将inquireheight()函数加入fruittree类别中──
class tree
品种
年龄
高度
end class
class fruittree
inherits tree
成熟月份
价格
function computeamount(重量)
computeamount = 重量 * 价格
end function
function inquireheight()
inquireheight = 高度
end function
class bamboo
inherits tree
用途
end class
于是fruittree类别之对象具有同样的行为──对computeamount()和inquireheight()讯息有所反应﹐且反应过程也相同﹐只是反应结果有所不同。写程序时﹐可认为fruittree类别之对象共同享用computeamount()及inquireheight()函数。也可认为各对象内﹐各有一份computeamount()函数及一份inquireheight()函数﹐以便处理这两种讯息。
请看个主程序﹕
protedted sub form1_click( .... )
dim amount as double
dim height as double
dim a as new fruittree( "peach", 8, 2.1, 3, 20)
dim k as new fruittree( "pineapple", 2, 0.5, 6, 10)
amount = a.computeamount( 25 )
height = a.inquireheight()
messagebox.show("amount= " + str(amount) + "height= " + str(height))
amount = k.computeamount( 25 )
height = k.inquireheight()
messagebox.show("amount= " + str(amount) + "height= " + str(height))
end sub
因fruittree类别含有computeamount()及inquireheight()两函数﹐所以对象 a及 k皆能接受这两种讯息﹐并处理之。至于其它的讯息﹐因无函数来支持(处理)﹐fruittree之对象无法接受之。您可继续把新函数加入fruittree类别中﹐使其对象拥有更丰富之行为﹐亦即能接受更多样化之讯息。换句话说﹐对象之功能就更多了。上述程序输出如下﹕
amount = 500 height = 2.1
amount = 250 height = .5
8. 着手写 vb.net程序
上节之主程序中﹐我们是假设对象 a及 k之内部已有资料了。也许您想问道﹕如何把资料存入对象内呢﹖很简单﹗当您有这种需要时﹐就设计一个函数﹐并加入类别中﹐由它担任资料的输入工作。资料输入对象中﹐也是对象之行为﹐一旦您将此函数加入类别之后﹐对象就能接受讯息﹐并且处理它。以下的实际vb程序﹐让您了解详细的情形了。这程序叫oop01-01:
'ex01.bas
imports system.componentmodel
imports system.drawing
imports system.winforms
'-----------------------------------------------------------------
class tree
public varity as string
public age as integer
public height as double
end class
class fruittree
inherits tree
public month as integer
public price as double
public function computeamount(byval weight as single) as double
computeamount = weight * price
end function
public function inquireheight() as double
inquireheight = height
end function
public sub setprice(byval pr as double)
price = pr
end sub
public sub setheight(byval hei as double)
height = hei
end sub
end class
class bamboo
inherits tree
public usage as string
end class
'-----------------------------------------------
public class form1
inherits system.winforms.form
public sub new()
mybase.new()
form1 = me
'this call is required by the win form designer.
initializecomponent()
'todo: add any initialization after the initializecomponent() call
end sub
'form overrides dispose to clean up the component list.
public overrides sub dispose()
mybase.dispose()
components.dispose()
end sub
#region " windows form designer generated code "
.......
#end region
protected sub form1_click(byval sender as object,
byval e as system.eventargs)
dim a as new fruittree()
dim k as new fruittree()
a.setprice(20)
a.setheight(2.1)
k.setprice(10)
k.setheight(0.5)
dim amount as double
dim height as double
amount = a.computeamount(25)
height = a.inquireheight()
messagebox.show(str(amount) + "元 , " + str(height) + "公尺", "结果")
amount = k.computeamount(25)
height = k.inquireheight()
messagebox.show(str(amount) + "元 , " + str(height) + "公尺", "结果")
end sub
end class
当您把这程序输入计算机﹐并利用vb执行它﹐则计算机输出结果如下﹕
500元, 2.1公尺
250元, .5公尺
请注意﹕这程序中有数个public专用字﹐此刻您不要为它们而伤脑筋﹐此后各章将详细说明之。现在您必须了解之重点是﹕
(1) 如何表明您所设计之类别﹐以及类别之间的父子关系。
例如﹐类别关系是﹕
在程序里﹐从上层类别开始﹐依照由上而下之顺序逐一把各类别叙述清楚。各类别所属之数据项(变量)﹐也得说明清楚。
(2) 如何把函数加入类别中﹐以支持对象之行为﹐使对象能接受讯息、进行运算并输出结果。
例如﹕fruittree已加入 4 个函数﹐使得fruit_tree类别之对象能接受并处理 4种讯息。
为了让对象能接受并处理讯息﹐必须把适当的函数加入类别中﹔因之﹐类别内含有两种重要成份──
1.数据项
2.函数
我们称这数据项为类别之「资料成员」(data member) ﹔并称这函数为类别之「成员函数」(member function)。例如:fruittree类别含两个资料成员──
成熟月份
价格
fruittree类别含 4个成员函数──
computeamount()
inquireheight()
setprice()
setheight()
(3) 如何产生对象。
如果您把类别视为一种资料型态(data type )﹐那就轻而易举了。想产生两个fruittree类别之对象﹐就写指令如下﹕
dim a as new fruittree()
dim b as new fruittree()
能以两种方法了解上述之指令﹕
1. 把fruittree视为类别﹐则a, k就是对象﹔则此指令就宣告两个「对象」(object)。
2. 把fruitttree视为一种资料型态(data type) ﹐则 a , k 就是fruittree型态之变量﹔则此指令宣告两个「变量」(variable)。
综合上述两种看法﹐您可认为﹕fruitttree是一种「型态」﹐a 和k 是「变量」﹐而类别型态之变量就是「对象」(object)。
(4) 对象中含有那些资料。
类别的父子关系﹐决定了对象之「继承」(inheritance) 关系﹐也决定对象中所含有之数据项。例如﹕fruittree是tree之「子类别」(subclass)﹐则fruittree类别之对象继承tree类别内之数据项。所以指令──
dim a as new fruittree()
产生了对象 a﹐它含有 fruittree 类别内之「资料成员」﹐也含有tree类别内之「资料成员」。
(5) 如何把讯息送给对象。
讯息与对象之关系可表示如下﹕
程序的写法为﹕
例如﹕ a.setprice( 20.0 )
及 a.setheight( 2.1 )
当计算机执行了这两个指令﹐亦即对象 a接受到这两个讯息﹐则 a之内容会有所变化﹔对象内部之变化也是一种行为﹐是对象对讯息之反应。此时tree类别的height值为 2.1﹐price 值为 20.0 。如果想把传回之结果存入变量中﹐程序写法为﹕
例如﹕
当计算机执行这两个指令﹐即把此二讯息送给对象 a﹐则 a会传回值﹐并经由 "="运算而存入变量中。于是amount值为 500元﹐而height值为 2.10 公尺。
习题
[1]「马上相逢无纸笔﹐凭君传语报平安」在此句话中﹐牵涉到几个「人」对象呢﹖其传递了什么讯息﹖其讯息对这些「人」对象之行为会有何影响呢﹖
[2] 林老师请小芳打电话向小美说﹕「祝你生日快乐」。可表示如下﹕
小美. 打电话(「祝您生日快乐」)
或者 小芳. 请打电话(小美﹐「祝您生日快乐」)
或者 林老师. 打电话(小芳﹐小美﹐「祝您生日快乐」)
何者较合理﹖理由何在﹖
[3] 有对男女朋友﹐互相询问对方的母亲的生日﹐该如何表达其讯息传递情形呢﹖
[4] 当您要求银行人员替您算出某帐户本月的利息时﹐其讯息可表示为﹕
银行人员. 计算利息(帐户)
或者 帐户. 计算利息()
何者较合理呢﹖