面向对象总结

面向对象总结

1.面向过程思想:一步一步的完成某个需求。侧重与过程。

2.面向对象:面向对象是基于面向过程的。侧重与结果。

3.面向对象思想特点:A.是一种更符合我们思想习惯的思想。

B.将复杂的事情的简单化

C.从执行者变成指挥者

4.Java语言最基本的单位是类。

5.类与对象:类:是一组相关属性和行为的抽象事物

对象:是该类事物的具体体现

6.类的组成:成员变量、成员方法(没有static修饰)的方法

7.创建类的对象:Phone p = new Phone();

8.成员变量的使用 p.变量;

9.成员方法的使用 p.方法名();

10.成员变量和局部变量的区别:A:在类中的位置不同

成员变量:类中方法外

局部变量:方法内或方法声明上

B:在内存的位置不同

成员变量:在堆内存

局部变量:在栈内存

C:生命周期不同

成员变量:随着对象的存在而存在,反之消失而消失

D:初始化值

成员变量 有默认初始化值

局部变量 没默认初始化值,必须赋值使用

11.形式参数问题:形式参数是基本类型的,形参的改变不影响实际参数

形式参数是引用类型的,形参的改变影响实际参数

12.匿名对象:就是没有名字的对象

应用场景:A:调用方法(对象调用方法仅仅一次)

B:作为实际参数传递

13.封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处:提高代码的复用性

提高代码的安全性

体现:将不需要对外提供的内容隐藏起来,对外提供公共访问方式

private :私有的意思。修饰成员变量和成员方法,被修饰的内容只能在本类中访问

14.this 代表当前类的对象。

应用场景:局部变量隐藏成员变量时。

15.构造方法:作用:给对象的数据进行初始化

各式特点:A:方法名和类名相同

B:没有返回值类型

C:没有返回值

注意事项:A:操作者不提供构造方法,系统会默认自己提供无参构造 B:如果操作者已经提供,系统将不再会提供

C:构造方法也是可以重载的。

16.成员方法:去掉static的方法。 根据返回值类型分为: void类型 非void类型 根据参数列表分为: 无参 带参的

17.static 关键字:作用:修饰成员变量和成员方法

特点:A:随着类的加载而加载

B:优先于对象存在

C:被类的多有对象共享(也是判断是否使用static的条件) D:可以通过类名调用

注意事项:A:在静态方法中没有this关键字(static是随着类的加载而加载,而this

是随着对象的创建而存在

B:静态方法只能访问静态的成员变量和成员方法

18.继承:多个类中具有相同的属性和行为时,提取出来定义到一个类中。然后多个类就和该类

有了关系,这个关系就是继承。

格式: class 子类名 extends 父类名{}

父类: 又称基类或超类

子类:又称派生类

19.继承的好处:A:提高了代码的复用性

B:提高了代码的维护性

C;是多态的前提

弊端:让类与类之间的关系紧密了,高耦合

开发推荐:高内聚,低耦合

特点:Java只支持单继承,可以多层继承

继承中类之间体现的是:is a 的关系

注意事项:A:子类只能继承父类所有非私有的成员变量和方法

B:子类不能继承父类的构造方法,但可以通过super关键字去访问 C:不要为了部分功能失去继承

继承间成员变量的关系:A:名字相同,对对应访问

B:名字不同,就近原则(子类局部--子类成员--父类成员--没有报错)

继承间成员方法的关系:同变量的关系

继承间构造方法的关系:子类中的所有构造方法都会默认访问父类的无参构造 为什么呢? 子类继承父类,子类初始化之前,先初始化父类的。 每个子类的构造方法的第一行有默认的super(); 假如父类没有无参构造:A :访问父类的带参构造

B:使用本类的一个构造,但必须要有子类的一个构造访问父类的构造

this(...)和super(...)必须出现在第一条语句(在后面会造成父类数据多次初始化) Super关键字:代表父类存储空间的标识(看以看成父类的对象)

this和super的区别:A:成员变量:this.成员变量 本类的成员变量

Super.成员变量 父类的成员变量

B:构造方法:this.(....) 同上 C:成员方法:this.成员方法(); 同上

20.代码块:在Java中,使用{}括起来的。分为局部代码块、构造代码块、静态代码块、同步代码块

局部代码块:位置:在方法中出现

作用:限定变量生命周期,及早释放,提高内存利用率

构造代码块:位置:类中方法外

作用:每次调用构造方法都执行,并且早于构造方法执行 静态代码块:位置:类中方法外并加static修饰

作用:用于给类进行初始化,在加载类的时候就执行,并且就执行一次

三个代码块的执行顺序:静态代码块---构造代码块---局部代码块

21.方法重写:父类与子类中出现方法声明一模一样的情况。

方法重写(override)和方法重载(overload)的区别?

方法重载在同一类中方法名相同,参数列表不同的方法,能够改变返回值类型

方法重写出现在父类与子类中方法声明一模一样的情况。不能改变 注意事项:A:父类私有方法不能被重写

B:子类重写父类方法权限不能更低

C:父类静态方法,只能通过静态方法重写

22.final关键字:最终的意思,可以修饰变量、方法、类。

final修饰:变量 变量不能再改动,成为常量

方法 方法不能被重写

类 类不能被重写

基本类型: 基本类型的值不能再改动

引用类型: 引用类型的地址值不能改动,地址内部的内容可以改动 final的初始化时机: A:定义的时候就赋值(推荐)

B;构造方法完毕前赋值

23.多态:同一事物在不同时刻表现出不同的状态。

前提:A:有继承关系

B:有方法重写

C:父类引用指向子类对象

成员访问特点:A:成员变量 编译看左边,运行看左边

B:成员方法 编译看左边,运行看右边(方法重写)

C:静态成员方法 编译看左边,运行看左边(静态方法为类所有) 多态的好处:A:提高代码的维护性(继承)

B:提高代码的扩展性(多态)

弊端:不能访问子类特有的功能

解决方法:A:创建子类最想进行访问

B:父类引用指向子类对象

多态中的转型问题:A:向上转型 子类--父类 Fu f = new Zi(); 父类引用指向子类对象

B:向下转型 父类-子类 Zi z = (Zi)f; 父类引用转向子类对象(可能类型转换异常)

24.抽象类:有些事物无法具体表达,定义为抽象的。

特点:A:抽象类个抽象方法必须用abstract修饰

B:抽象类中不一定有抽象方法,但有抽象方法的一定是抽象类 C:抽象类不能实例化(通过具体的子类实例化)

D:抽象类的子类要么是也是抽象类,要么重写抽象类的所有抽象方法。 抽象类的作用:强制要求子类重写某些方法。

抽象类的成员:A:成员变量:可以是变量也可以是常量

B:构造方法:有,不能实例化,用于子类访问父类数据进行初始化 C:成员方法:可以是抽象的,也可以是非抽象的

抽象类的两个小问题:

1:一个类如果没有抽象方法是否可以?没有抽象方法的抽象类有什么作用? 答:可以,不让别人创建对象,必须通过子类创建对象。

2:abstract不能和那些修饰符共存?

答:abstract修饰的方法必须通过子类重写。所以不能和

private(私有方法不能被重写),final(修饰的方法不能被重写),static和abstract共存无意义

25.接口:实际生活中,有些功能后期需要,开始没有这样Java就提供了这个功能--接口。

特点:A:定义接口必须要用interface表示。 格式:interface 类名{}

B:类实现接口用implements表示。 格式:class 类名 implements 接口名{}

C:接口不能实例化。由接口的具体类实例化,多态的一种(接口多态) D:接口的实现类 要么是抽象类,要么重写接口中的所有方法 多态的前提:A:有继承或实现关系

B:有方法重写

C:有父类引用指向子类对象或父类接口指向实现类对象

多态的分类:A:具体类多态 B:抽象类多态 C:接口多态

26.抽象类和接口的区别:

A:成员区别

抽象类:成员变量:可以变量也可以常量

构造方法:有

成员方法:可以是抽象的也可以是非抽象的

接口:成员变量:只能是常量(有默认修饰符public static final)

构造方法:没有

成员方法:只能是抽象方法(有默认修饰符 public abstract) B:关系区别

类与类:继承关系,只能单继承,但可以多层继承

类与接口:实现关系,可以单实现也可以多实现,也可以在继承一个类的同时实现多个接口

接口与接口:继承关系,可以单继承也可以多继承

C:设计理念区别

抽象类被继承体现的 is a 的关系 体现共性

接口被实现体现的是 like a的关系 体现扩展功能

27形式参数问题: 数据类型:基本类型:byte、short、int、long、char、float、double、boolean

引用类型:数组、类、接口

A:基本类型:要的是该类型的具体数据值

返回值--基本类型 返回的是也是该类的具体数据值

B:引用类型:要的是该引用类型的对象

A:类 要的是该类或其子类对象(地址值)

返回值--类:返回的是该类或其子类对象(地址值)

B:抽象类 要的是其子类对象(地址值)

返回值--抽象类 返回的是其子类对象(地址值)

C:接口 要的是其实现类对象(地址值)

返回值--接口 返回其实现类对象

D:数组 要的是该数据类型的数组对象

28.包:其实就是文件夹。

作用:对类进行分类管理

定义包:package 包名;

注意事项:A:package定义必须在第一条有效可执行语句

B:package在一个Java文件中只能有一个

C:如果没有package,默认无名

导包: 格式: import 包名;

package ,import,class顺序

package > import > class

仅一个 可以多个 可以多个

29.内部类:把类A定义到类B中,则A成为B的内部类

访问特点:A:内部类可以直接访问外部类的所有成员包括私有

B:外部类访问内部类的成员,必须创建对象

内部类位置:成员位置:成员内部类

局部位置L局部内部类

成员内部类:外界创建对象 : Outer.Inner oi = new Outer().new Inner();

成员内部类的修饰:A:private 为了我们访问数据的安全性

B:static 为了访问数据的方便性

面试题:为什么局部内部类访问局部变量要加final修饰?

因为局部变量会随着方法的调用完毕而消失,这个时候局部对象并没有立即消失,为了继续使用这个数据,加final修饰,这样存储于堆内存的是一个常量。通过反编译器查看.

匿名内部类:就是没有名字的内部类,内部类的简化写法。

前提:A:存在一个类或者借口。

B:这里的类可以是具体类也可以是抽象类。

格式: new 类名或接口名(){重写方法;};

本质:是一个继承了类或者实现接口的子类匿名对象。

 

第二篇:js面向对象开发总结

JavaScript面向对象编程

1、引言

JavaScript是一种解释性的,基于对象的脚本语言(an interpreted, object-based scripting language)。JavaScript 基于客户端运行,目前基本上所有的浏览器都支持JavaScript。1995年首次出现时,JavaScript的主要目的还只是处理一些输入的有效性验证,随着互联网的蓬勃发展,JavaScript的应用越来越广泛,特别是近几年AJAX技术(Asynchronous JavaScript and XML)的发展,更使JavaScript的应用达到了一个新的高度。在AJAX技术中,JavaScript是一项关键技术,请求的发送、接收、接收数据后的界面处理都需要使用JavaScript技术,这对JavaScript语言提出了新的需求,本文从JavaScript的基本特点出发,模拟出了面向对象编程的大部分特点,使JavaScript摆脱了以往脚本语言杂乱无章、难以阅读、难以维护的形象,而具有了面向对象特性,极大的方便了JavaScript的开发、维护,提高了软件开发效率。

2JavaScript的基本特点

JavaScript是解释性的,基于对象的脚本语言。它有下面几个显著特点,这几个特点在后面的面向对象特性模拟中会反复用到,因此这里先详细说明这几个特点。

解释型语言:JavaScript是一种解释性语言,解释性语言相对于编译型语言,编译型语言必须先通过编译才能执行,而解释性语言不需要编译,直接从上到下解释执行,一边解释一边执行,这就决定了解释性语言的代码是有先后顺序的,需要执行的代码必须已经解释过。因此,JavaScript需要注意代码的先后顺序。

弱类型语言:JavaScript是一种弱类型语言,弱类型语言相对于强类型语言,大部分面向对象语言都是强类型语言,强类型语言是一种需要强制类型定义的语言,它要求每个变量都确定某一种类型,它和别的类型转换必须显式转换。弱类型语言是一种类型可以被忽略的语言,它在变量定义时不指定某一类型,在执行时通过执行结果才能确定类型,不同类型之间不需要通过显式转换就可以转换。

动态添加属性和方法:这个特点是指可以动态为某个对象添加以前没有的属性和方法。这个特点使JavaScript非常灵活,正因为有了这个特点,JavaScript的面向对象编程才有了可能。

prototype(原型)属性:JavaScript是一种基于对象的语言,JavaScript中的所有对象,都具有prototype属性。prototype属性返回对象的所有属性和方法,所有 JavaScript 内部对象都有只读的 prototype 属性,可以向其原型中动态添加属性和方法,但该对象不能被赋予不同的原型。但是自定义的对象可以被赋给新的原型。

3、面向对象的基本特点

面向对象有下列三个主要特点:封装、继承和多态。这里先详细说明这几个特点,后面几个部分分别在JavaScript中实现这些特点,从而实现完整的面向对象模拟。

封装:封装就是把各种方法和变量合并到一个类,用这个类代表某个对象为完成一定的任务所能保存的范围以及它能执行的操作。封装隐藏了方法执行的细节。

继承:继承就是根据现有类的方法和成员变量生成新的类的功能。

多态:多态就是对象随着程序执行而使其形式发生改变的能力。

4JavaScript语言基础

4.1数据类型

基本数据类型:Number, String, Boolean, Function, Object, Array, null, undefined,注意null和undefined的区别。

日期和时间:日期类型并不是JavaScript的基本数据类型,但JavaScript提供了一个处理日期的类:Date,用法如下:

正则表达式:主要用于对文本进行模式匹配,实现对文本的查找和替换操作。在JavaScript中,提供了一个RegExp类来处理正则表达式,创建方式和Date一样,用关键字new就可以创建,如var re = new RegExp();

和Date不一样的地方在于,虽然RegExp类也不是JavaScript的基本数据类型,但我们在创建正则表达式对象时,可以不需要用new关键字就可以创建,如 var re = /[1-9][0-9]*/; 这样就直接定义了正则表达式对象,因为在JavaScript中,一对斜线中包括一个文本就认为构成了一个正则表达式对象。

下面就示例用正则表达式判断输入的Email和手机号是否合法:

错误对象:JavaScript中定义了几个用于处理错误类型的类,有:Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError。和Java中的异常处理方式类似,JavaScript中的错误对象可以用try...catch...finally语句来处理,示例如下:

4.2 变量

JavaScript是一种弱类型的语言,这就意味着一个JavaScript变量可以指向任何数据类型,例如:

var i = 10;

i = “ten”;

变量的作用域

var scope = “global scope”;    // 全局变量

function checkscope() {

    var local = “local scope”;    // 局部变量

}

注意:除函数中的变量为局部变量外,其他的全部为全局变量。

4.3 函数

JavaScript中:

function add(a, b) {

   return a + b;

}

Java中:

public int add(int a, int b) {

   return a + b;

}

函数的参数: arguments对象

在一个函数中,会有一个隐含的arguments对象来保存函数的参数,这样在有些时候,我们在定义函数时,可以不明确指定函数所需要的参数,如下:

5、封装的实现

下面以一个详细的示例来说明常用的私有实例成员、公有实例成员和公有静态成员的封装。

JavaScript语言中类的定义和函数的定义都是使用function关键字,使用function定义的过程,即可以看成是类的定义,也可以看成是函数的定义。从示例代码中可以得出:

·         私有属性和方法的定义,直接在类内部定义一个变量,因为这个变量的作用域只限定在类内部,外部不能使用,因此这样定义的属性是私有属性,私有方法的定义也类似。

·         公有属性和方法的定义,通过定义一个私有变量me等于this,然后动态添加me变量的属性和方法,最后把me变量作为创建的实例对象返回。这样给me变量添加的属性和方法在类外部可以使用,也就是共有属性和方法。

·         构造函数的定义,构造函数是在创建一个对象时,自动执行的一个函数。在Java,C#等面向对象的语言中,只要定义一个函数和类名相同即可。在JavaScript中,可以随便定义一个私有函数,这个函数需要在类定义体中执行,这样的函数即成为构造函数,需要注意的是,为了确保构造函数中的代码都已经被解释过,构造函数最好放在类定义的最后。

·         类静态方法的定义,类静态方法是指不需要通过类实例来调用,而是可以直接通过类名来调用的方法。在Java,C#等面向对象语言中,一般是通过关键字static来指明一个方法是静态方法。在JavaScript中,没有static关键字,不能在类的定义体中实现静态方法,必须在类的定义体外,通过直接在类上动态添加方法来定义静态方法。需要注意,JavaScript静态方法中不能访问类的公有属性和公有方法,这和Java,C#等语言是一致的。

·         类的公有属性和公有方法也可以使用prototype来实现, 但是使用prototype有以下几个注意点:需要定义在类定义体外,和Java等语言的封装习惯不一致;prototype方式不能访问类的私有属性。

·         JavaScript不能实现只读属性、只写属性的定义,所有的公有属性都是可读可写。

6、继承的实现

JavaScript中没有Java,.Net中实现继承的关键字,JavaScript中的继承都是通过JavaScript语言本身的特性模拟出来的,可以通过两种方式实现继承:

l  创建对象方式

定义一个变量me,赋予父类实例,这样me就有了父类的属性和方法,然后给me增加子类的属性和方法,最后把me变量作为创建的实例对象返回。这样定义的类就有了父类的属性和方法,即实现了继承。

l  原型(prototype)方式

首先封装好子类的属性和方法,然后创建一个父类实例附给子类的prototype属性,这样子类就有了父类的属性和方法,即实现了继承。

这两种方式都实现了继承,但是和Java,.Net等面向对象语言相关,JavaScript中模拟的继承还要以下问题:

l  不能定义保护的方法和属性。

l  不能继承父类的静态方法。

7、多态的实现

多态主要包括重载(overload)和覆盖(override),重载是指同一个名字的函数或方法可以有多个实现,他们依靠参数的类型或参数的个数来区分识别。而覆盖是指子类中可以定义与父类中同名的方法,这些方法定义后,在子类的实例化对象中,父类中继承的这些同名方法将被隐藏。

由于JavaScript的弱类型性,JavaScript在定义函数时,不需要指定函数参数的类型和个数,这种特性为重载的实现提供了便利。如下函数:

函数调用时可以传入string,也可以传入number,或别的类型,在函数实现体中可以使用typeof函数得到传入参数的类型,从而实现不同的功能。这样虽然是一个函数实现体,但是也有了多个实现,即重载。JavaScript中另外一种比较常见的重载方式是通过函数的arguments对象来实现,这种方式已在前面讲过,不再赘述。

JavaScript中覆盖的实现,只需在子类中定义一个与父类同名的方法即可。

8、静态类的实现

静态类,是一种不能被实例化,并且只包含有静态成员的类。在Java,C#等面向对象语言中,一般使用static关键字来指明类是静态类,JavaScript中没有static关键字,但是可以通过实例化匿名函数来实现静态类。如下:

UtilTool其实是一个对象,只是这个对象属于匿名类,该类在创建完UtilTool这个对象后,就不能再被使用了。而UtilTool是一个对象,不是一个 function,所以不能作为一个类被实例化,因此,它就相当于一个静态类。

JavaScript调试

JavaScript的执行环境是浏览器,目前没有像Eclipse和Visual Studio等比较高级的IDE,调试就需要借助外部的调试工具。

IE下的调试工具主要有Office工具中的“站点调试”和Visual Stutio。

Firefox下的调试工具为著名的firebug。

树形控件是一种人们熟悉的用户界面控件,广泛地用来显示层次型数据。

树形控件具有独特的扩展和折叠分支的能力,能够以较小的空间显示出大量的信息,一目了然地传达出数据之间的层次关系。凡是熟悉图形用户界面的用户,都能够自如地运用树形控件。


图一:用javascript实现的树形控件

HTML本身不支持树形控件,但我们可以通过一些javascript脚本代码实现。为了提高控件的可重用性,我们要充分运用javascript对面向对象编程技术的支持。本文的树形控件适用于IE 4+和Netscape 6.x,应当说这已经涵盖了当前的主流浏览器。

一、javascript与面向对象

面向对象的编程有三个最基本的概念:继承,封装,多态性。继承和封装这两个概念比较好理解,相对而言,多态性这个概念就比较难于掌握和运用。一般而言,多态性是指以多种形式表现的能力。在面向对象编程技术中,多态性表示编程语言拥有的一种根据对象的数据类型或类的不同而采取不同处理方式的能力。

在“纯”面向对象的语言中,例如Java,多态性一般与类的继承密不可分。也就是说,必须定义一种类的层次关系,处于顶端的是抽象类,处于下层的是各种具体的实现。抽象类定义了子类必须实现或覆盖的方法,不同的子类根据自己的需要以不同的方式覆盖抽象类的方法。

例如,计算圆面积和矩形面积的公式完全不同,按照面向对象的设计思路,我们要先定义一个抽象类Shape,Sharp类有一个findArea()方法,所有从Shape类派生的子类都必须实现findArea()方法。然后,我们定义一个代表矩形的Rectangle类,一个代表圆的Circle类,这两个类都从Shape类继承。Rectangle类和Circle类分别实现findArea()方法,两者用不同的计算公式计算面积。最终达到这样一个目标:不论对象属于Shape的哪一种子类(Rectangle或Circle),都可以用相同的方式调用findArea()方法,不用去管被调用的findArea()采用什么公式计算面积,从而有效地隐藏实现细节。

javascript语言不支持以类为基础的继承,但仍具有支持多态性的能力。javascript的继承是一种基于原型(Prototype)的继承。实际上,正如本文例子所显示的,这种继承方式简化了多态性方法的编写,而且从结构上来看,最终得到的程序也与纯面向对象语言很接近。

二、准备工作

整个树形控件由四部分构成:图形,CSS样式定义,HTML框架代码,javascript代码。从图一可以看出,树形控件需要三个图形,分别表示折叠的分支(替换webdesign.chinaitlab.com/javascript/closed.gif)、展开的分支(open.gif)和叶节点(替换webdesign.chinaitlab.com/javascript/doc.gif)。

下面是树形控件要用到的CSS样式定义:

< style>
body{
font: 10pt 宋体,sans-serif; color: navy; }
.branch{
cursor: pointer;
cursor: hand;
display: block; }
.leaf{
display: none;
margin-left: 16px; }
a{ text-decoration: none; }
a:hover{ text-decoration: underline; }
< /style>

CSS规则很简单:body规则设置了文档的字体和前景(文字)颜色。branch规则的用途是:当鼠标经过拥有子节点的节点时,指针会变成手的形状。之所以要定义两个cursor属性,是因为IE和Netscape使用不同的属性名称。在leaf规则中设置display属性为none,这是为了实现叶节点(不含子节点的最终节点)的折叠效果。在脚本代码中,我们通过把display属性设置成block显示出节点,设置成none隐藏节点。

三、脚本设计

本文实现的树形控件包含一个tree对象,tree对象拥有一个branches子对象集合;每一个branch(分支)对象又拥有一个子对象的集合。子对象可以是branch对象,也可以是leaf(树叶)对象。所有这三种对象分别实现一个多态性的write()方法,不同对象的write()方法根据所属对象的不同而执行不同的操作,也就是说:tree对象的write()方法与branch对象的write()方法不同,branch对象的write()方法又与leaf对象的write()方法不同。另外,tree和branch对象各有一个add()方法,分别用来向各自所属的对象添加子对象。

在HTML文档的部分加入下面这段代码。这段代码的作用是创建两个Image对象,分别对应分支打开、折叠状态的文件夹图形。另外还有几个工具函数,用于打开或折叠任意分支的子元素,同时根据分支的打开或折叠状态相应地变换文件夹图形。

< script language="javascript">
var openImg = new ..Asset not found..;
openImg.src = "open.gif";
var closedImg = new ..Asset not found..;
closedImg.src = "替换webdesign.chinaitlab.com/javascript/closed.gif";

function showBranch(branch){
var objBranch = document.getElementById(branch).style;
if (objBranch.display=="block")
objBranch.display="none";
else
objBranch.display="block";
swapFolder('I' + branch);
}

function swapFolder(img){
objImg = document.getElementById(img);
if (objImg.src.indexOf('替换webdesign.chinaitlab.com/javascript/closed.gif')>-1)
objImg.src = openImg.src;
else
objImg.src = closedImg.src;
}
< /script>

代码预先装入图形对象,这有利于提高以后的显示速度。showBranch()函数首先获得参数提供的分支的样式,判断并切换当前样式的显示属性(在block和none之间来回切换),从而形成分支的扩展和折叠效果。swapImage()函数的原理和showBranch()函数基本相同,它首先判断当前分支的图形(打开的文件夹还是折叠的文件夹),然后切换图形。

四、tree对象

下面是tree对象的构造函数:

function tree(){
this.branches = new Array();
this.add = addBranch;
this.write = writeTree;
}

tree对象代表着整个树形结构的根。tree()构造函数创建了branches数组,这个数组用来保存所有的子元素。add和write属性是指向两个多态性方法的指针,两个多态性方法的实现如下:

function addBranch(branch){
this.branches[this.branches.length] = branch;
}

function writeTree(){
var treeString = '';
var numBranches = this.branches.length;
for (var i=0;i <NUMBRANCHES;I++)
treeString += this.branches[i].write();
document.write(treeString);
}

addBranch()方法把参数传入的对象加入到branches数组的末尾。writeTree()方法遍历保存在branches数组中的每一个对象,调用每一个对象的write()方法。注意这里利用了多态性的优点:不管branches数组的当前元素是什么类型的对象,我们只需按照统一的方式调用write()方法,实际执行的write()方法由branches数组当前元素的类型决定——可能是branch对象的write()方法,也可能是leaf对象的write()方法。

必须说明的是,虽然javascript的Array对象允许保存任何类型的数据,但这里我们只能保存实现了write()方法的对象。象Java这样的纯面向对象语言拥有强健的类型检查机制,能够自动报告类型错误;但javascript这方面的限制比较宽松,我们必须手工保证保存到branches数组的对象具有正确的类型。

五、branch对象

branch对象与tree对象相似:

function branch(id, text){
this.id = id;
this.text = text;
this.write = writeBranch;
this.add = addLeaf;
this.leaves = new Array();
}

branch对象的构造函数有id和text两个参数。id是一个唯一性的标识符,text是显示在该分支的文件夹之后的文字。leaves数组是该分支对象的子元素的集合。注意branch对象定义了必不可少的write()方法,因此可以保存到tree对象的branches数组。tree对象和branch对象都定义了write()和add()方法,所以这两个方法都是多态性的。下面是branch对象的add()和write()方法的具体实现:

function addLeaf(leaf){
this.leaves[this.leaves.length] = leaf;
}

function writeBranch(){
var branchString =
'< span class="branch" ' + onClick="showBranch(\'' + this.id + '\')"';
branchString += '>< img src="替换webdesign.chinaitlab.com/javascript/closed.gif" id="I' + this.id + '">' + this.text;
branchString += '< /span>';
branchString += '< span class="leaf" id="';
branchString += this.id + '">';
var numLeaves = this.leaves.length;
for (var j=0;j< numLeaves;j++) branchString += this.leaves[j].write();
branchString += '< /span>';
return branchString;
}

addLeaf()函数和tree对象的addBranch()函数相似,它把通过参数传入的对象加入到leaves数组的末尾。

writeBranch()方法首先构造出显示分支所需的HTML字符串,然后通过循环遍历leaves数组中的每一个对象,调用数组中每一个对象的write()方法。和branches数组一样,leaves数组也只能保存带有write()方法的对象。

六、leaf对象

leaf对象是三个对象之中最简单的一个:

function leaf(text, link){
this.text = text;
this.link = link;
this.write = writeLeaf;
}

leaf对象的text属性表示要显示的文字,link属性表示链接。如前所述,leaf对象也要定义write()方法,它的实现如下:

function writeLeaf(){
var leafString = '< a href="' + this.link + '">';
leafString += '< img src="替换webdesign.chinaitlab.com/javascript/doc.gif" border="0">';
leafString += this.text;
leafString += '< /a>< br>';
return leafString;
}

writeLeaf()函数的作用就是构造出显示当前节点的HTML字符串。leaf对象不需要实现add()方法,因为它是分支的终结点,不包含子元素。

七、装配树形控件

最后要做的就是在HTML页面中装配树形控件了。构造过程很简单:创建一个tree对象,然后向tree对象添加分支节点和叶节点。构造好整个树形结构之后,调用tree对象的write()方法把树形控件显示出来。下面是一个多层的树形结构,只要把它加入标记内需要显示树形控件的位置即可。注意下面例子中凡是应该加入链接的地方都以“#”替代:

< script language="javascript">
var myTree = new tree();
var branch1 = new branch('branch1','javascript参考书');
var leaf1 = new leaf('前言','#');
var leaf2 = new leaf('绪论','#');
branch1.add(leaf1);
branch1.add(leaf2);
myTree.add(branch1);

var branch2 = new branch('branch2','第一章');
branch2.add(new leaf('第一节','#'));
branch2.add(new leaf('第二节','#'));
branch2.add(new leaf('第三节','#'));
branch1.add(branch2);

var branch3 = new branch('branch2','第二章');
branch3.add(new leaf('第一节','#'));
branch3.add(new leaf('第二节','#'));
branch3.add(new leaf('第三节','#'));
branch1.add(branch3);

myTree.add(new leaf('联系我们','#'));
myTree.write();
< /script>

上述代码的运行效果如图一所示。可以看到,装配树形控件的代码完全符合面向对象的风格,简洁高效。

从本质上看,用面向对象技术构造的树形控件包含一组对象,而且这组对象实现了纯面向对象的语言中称为接口的东西,只不过由于javascript语言本身的限制,接口没有明确定义而已。例如,本文的树形控件由tree、branch、leaf三个对象构成,而且这三个对象都实现了write接口,也就是说,这三个对象都有一个write()方法,不同对象的write()方法根据对象类型的不同提供不同的功能。又如,tree、branch对象实现了add接口,两个对象分别根据自身的需要定义了add()方法的不同行为。可见,多态性是面向对象技术中一个重要的概念,它为构造健壮的、可伸缩的、可重用的代码带来了方便。

http://www.haoxiai.net/wangzhanzhizuo/jiaobenyuyan/30468.html

练习题

1、     定义父类:Shape(形状)类,Shape只有一个属性color,并有相应的getColor和setColor方法。

2、     Shape类有两个子类:Rectangle(矩形)类和Circle(圆形)类,子类继承了父类的color属性和getColor、setColor方法。

3、     为两个子类增加相应的属性和getArea方法,可调用getArea方法获得矩形和圆形的面积。要求:用以上讲过的两种继承方式实现。

相关推荐