8.面向对象程序设计
8.1类和对象的概念
类:类是用来创建同 一类型的对象的“模板”,在一个类中定义了该类对象所应具有的成 员变量以及方法,
Think in ActionScript 3.0Ⅲ
。对象:对象是类的实例。
8.2类之间的关系
系统中的类有那些关系:依赖、关联(聚合、合成)、泛化、实现。
1.依赖:对于外部类或对象的引用;
5.关联:关联暗示两个类在 概念上位于相同的级别;
6.聚合:表示一种“拥有”关系,是 两个类之间一种整体 / 局部的关系;
7.合成:表示一种更强“拥有 ”关系,就像人和腿的关系一样。组合而成的新对象对组成部分的内容分配 和释放有绝对责任;
8.泛化:表现为继承 extends;
9.实现:表 现为实现 implements。
8.3 面向对象程序设计(OOP)
在面向对 象出现以前,结构化程序设计是程序设计的主流,结构化程序设计又称为面向过 程的程序设计。这种设计方法开发的软件稳定性、可修改性和可重用性都比较差 。
与过程相比对象是稳定的。面向对象的软件系统是由对象组成的,复杂 的对象是由比较简单的对象组合而成的。也就是说,面向对象方法学使用对象分 解取代了传统的功能分解。
面向对象的精髓在于考虑问题的思路是从现实 世界人类思维习惯出发的,只要领会了这一点,就领会了面向对象的思维方法。 万事万物皆为对象,大至日月星辰,小至沙粒微尘,都是对象。对象包容了一切 事物,不仅仅是那些看得见摸得着的是实体,如:地球、汽车、树叶,还包括那 些客观存在的事物,如:社会、互联网、朋友圈子等等,包罗万象。
以开 车为例,用面向过程的思想去考虑,那么你先得知道怎么启动,怎么踩油门,怎 么挂档。这些应该是司机的活,你要把这些步骤都实现出来。如果用面向对象的 思想,把自己看成领导,只需要下达命令,告诉它你要去哪里就行了(例如,调 用drive() 方法),具体怎么开,怎么踩油门,怎么挂档,不需要我们去管。
那么 dirve() 这个方法放到车里是否合适呢,是不是应该放到“司 机”类更合理呢?封装是很灵活的,没有对与错之分,只有好与更好,需要 具体问题具体分析。因为 dirve() 方法要用到油门和车档,而这些东西都在车里 面,因此如果将它封装到车这个类里面可能更好些。
下面我们通过对比面 向过程和面向对象的设计方式体会什么才是面向对象的思维。
8.4 出圈游 戏 —— 面向过程 VS 面向对象
8.4.1 游戏规则
假设 有5 个小孩儿手拉手围成一圈。从第一个小孩儿开始以顺时针方向依次报数 —— “1,2,3”,报 3的人出列,第四个人从1 开始重 新报数,报到 3 时再出列。如此下去,直到所有人全部出列为止,要求按照出列 的顺序输出他们的序号。
下面来看图理解,首先有5 个小孩围成一个圈:
图一、 5 个小孩儿围成一圈
图二、数到 3的小孩儿退出去
图三、再从2 号开始数三个人, 5 号退出,然后是2 号,最后是4 号。
最终输出的顺序应该是3、1、5、2、4。
8.4.2 出圈游戏 —— 面向过程(cirgame/ CircleGame1.as)
下面用面向过程的思想写这个程 序,通过读注释先来看一下这个程序:
//有5 个小孩儿围成的圈
var array:Array = new Array(5);
for (var i = 0; i < array.length; i++) {
// 如果元素值为 true 表示他在圈内,如果是false 表示不在圈内
array[i] = true;
}
// 圈内还剩多少人,最开始人都在,等于 array.length
var leftCount:int = array.length;
// 当前所报的数,初始为 0
var countNum:int = 0;
// 圈子的数组下标,表示当前指向的是谁
var index:int = 0;
while(leftCount > 0) {
if (array[index] == true) {
// 如果当前这个人在圈内则报数
countNum++;
if (countNum == 3) {
// 如果所报的数是3 则出列,剩余人数减1,并且下一 次从新开始报数
trace("out " + (index + 1));
array[index] = false;
leftCount--;
countNum = 0;
}
}
//数组下标增加
index++;
if (index == array.length) {
// 如果下标是最后一个位则归 0,因为这个圈是圆的
index = 0;
}
}
用array数组代表这个围成的圈,开始让圈数组中的每个元素都 为 true,表示它们都在圈内,如果设为 false 则表示不在圈内,后面报数的时 候就不予考虑了。
接下来定义三个变量分别表示圈内还剩多少人,所报的 数是多少和数组下标。
下面 while 循环开始,只有圈内还有人 (leftCount > 0)就进行循环,首先判断当前 index 所指的元素是否为真, 如果是则报数加 1,再判断是不是加到 3 了,如果是则打印出当前的数组下标, 再将该元素设为 false,剩余人数减1,下一次从新开始报数,
电脑资料
《Think in ActionScript 3.0Ⅲ》(http://meiwen.anslib.com)。最后让数组下标加 1,当指到最后时,将数组下标置为 0,因为这是一个圈, 要用循环的数组来表示。
8.4.3 出圈游戏 —— 面向对象 (cirgame/ CircleGame2.as)
回顾上一个例子,在面向过程的程序中, 明明是围成的一个圈儿,却要看成是一个数组;明明是一个个小孩儿却要看成是 数组的一个个元素。这不就是为了让计算机看懂吗?但是,面向对象是更加接近 人类的思维模式,我们在现实中看到的就是一个个小孩儿,怎么能说是数组?那 么这一个个小孩儿就是一个个对象,他们都是Kid。围成的这个圈,就是一个 KidCircle。很自然吧,比大自然还自然!下面来体会面向对象的设计思想:
package cirgame {
public class CircleGame2 {
public function CircleGame2() {
var kc:KidCircle = new KidCircle(5);
var countNum:int = 0;
var k:Kid = kc.head;
while (kc.count > 0) {
countNum++;
if (countNum == 3) {
trace(k.id + 1);
kc.remove(k);
countNum = 0;
}
k = k.right;
}
}
}
}
// 每个Kid都有自己的id,并且左右手还拉着其它的Kid
class Kid {
var id:uint;
var left:Kid;
var right:Kid;
}
// 这个圈子里可以加入或移除一些Kid
class KidCircle {
var count:uint = 0;
var head:Kid;
var rear:Kid;
function KidCircle(n:uint) {
for (var i = 0; i < n; i++) {
var kid:Kid = new Kid();
add(kid);
}
}
function add(kid:Kid):void {
kid.id = count;
if (count == 0) {
head = kid;
rear = kid;
kid.left = kid;
kid.right = kid;
} else {
rear.right = kid;
kid.left = rear;
kid.right = head;
head.left = kid;
rear = kid;
}
count++;
}
function remove(kid:Kid):void {
if (count <= 0) {
return;
} else if (count == 1) {
head = rear = null;
} else {
kid.left.right = kid.right;
kid.right.left = kid.left;
if (kid == head) {
head = kid.right;
} else if (kid == rear) {
rear = kid.left;
}
}
count--;
}
}
这段程序中设计了两个类,代表两类客观事物 —— 小孩(Kid)和圈子(KidCircle)。从8.4.1的图中可以确切地看到。Kid有三个 属性:id 号、左手和右手,左手拉着一个Kid,右手拉着一个Kid,因此left和 right存放两个Kid的引用。
下面是KidCircle类,代表围成的圈子,这个圈子可以加入或移除一些Kid,因 此有add和remove两个方法。head和rear两个成员变量用于指向队首和队尾的两个 Kid,因为些添加的Kid 要放在队尾(rear)的后面,因为这是一个圈子,所以还 需要让队尾的小孩儿拉住队首(head)的小孩儿,因此需要保存这两个成员变量 。
最后是测试类,主要的逻辑和前一个例子比较像,这里就不多解释了。
通过这个例子大家可以看出,我们无形之间就完成了一个数据结构 —— 双向循环链表。而前面面向过程的例子,实际上就是一个顺序的 存储结构 —— 线性表。
后面,我会带大家写一个贪吃蛇的游 戏,目的是学习面向对象编程的思想(并非该游戏本身),在贪吃蛇中我们就会 运用到类似于单向链表的结构,如果双向链表掌握了,那么单向一定没问题。
通过本节请大家认真体会面向对象的设计思想。一次学会,终身受用。