书城计算机网络综合应用软件设计
8724600000024

第24章 软件构造(3)

这种方法不仅可以避免有条件的检查和简化代码,而且它还使得对于客户代码对象的使用变得更清晰。这个重载New方法可以使用参数也可以不用参数,有很大的灵活性。实际上,通过重载,可以创建许多不同的构造函数,也可以利用许多种不同的方法来初始化我们的对象。在VB.NET中构造函数方法是可选的。但是只有一个例外,那就是当使用继承的时候,父类就只有一个构造函数需要参数。不像COM,.NET不是使用引用计数来决定对象是否被终止的。取而代之的是,它使用了一个有名的“垃圾收集”方案来终止对象。实际上,它的意思是在VB.NET中,不用预先定一个对象的终止方案,因此就不能准确地预测对象什么时候被终止的。下面我们详细探讨一下“垃圾收集”。

在.NET中,引用计数不是一个基础功能部分。相反,对象是通过一个“垃圾收集”机制被终止。在某特定的时间(这决定特殊的规则),一个任务会在所有的对象中运行来查找那些已经没有被引用的对象,并且将这些对象终止,即所谓的“垃圾收集”。

由以上的讨论可以知道,不能准确地知道对象是在什么时候被终止的。除去对象的所有引用之后,并不是意味着对象快速地被终止了。此时对象还存在于内存中,直到“垃圾收集”处理程序运行之后才将它从内存中清除。

“垃圾收集”的主要好处是它清除了由引用计数带来的循环应用问题。如果两个对象互相有引用,并且在程序中没有其他互相引用的代码时,“垃圾收集”程序就会发现它们并将它们终止。这一点在COM中是不可能做到的,因此它们将在内存中永远存在。“垃圾收集”还有另外一个潜在的性能优点:在对象被取消引用的时候不用花很多的精力在终止对象上;利用了“垃圾收集”,这个终止处理过程是在应用程序处于空闲状态时发生的,所以它减轻了对用户的影响。但是,“垃圾收集”也会发生在应用程序处在运行装载的时候,这时系统将会运行在较低的系统资源下。

另外,可以通过编写代码来手动触发“垃圾收集”处理程序:

System.GC.Collect()

以上这个处理过程要花一些时间,但是在想终止对象的时候也不必每次都执行这个处理过程。最好是这样来设计我们的应用程序:在最后终止对象的时候才将对象从内存中清除。

Finalize方法:

这个“垃圾收集”机制提供了一些功能,这些功能可以跟VB6.0中的Class_Terminate事件相媲美。当对象被终止的时候,“垃圾收集”处理的代码将调用Finalize方法,它就像Class_Terminate一样可以进行一些最后的内存清理工作。

Protected Overrides Sub Finalize()

(此处可以进行一些内存清理工作)

End Sub

以上的这些代码可以使用Protected(保护)作用域,也可以使用重载关键字。这里值得指出的是,这种方法是在对象被“垃圾收集”机制终止之前被调用的,所以它跟Class_Terminate事件是很相似的。

但是,还需要记得这种方法可以在对象被取消引用后被调用,它是通过最后一段客户代码来实现的。

实现Dispose方法:

在有些场合中,Finalize方法是不可接受的。如果有一个对象,它使用一些非常有限的宝贵的系统资源,比如数据库连接、文件处理或者系统锁住等。这时候就需要确保系统资源在对象被取消引用的时候被释放。为了实现这个目的,可以执行这样一种方法,它可以被客户代码调用,来强迫对象被清除并且释放系统资源。虽然这不是一个完美的解决方案,但是它确实是很有效的。习惯上,这个方法就取名为Dispose,其代码如下:

Public Sub Dispose()

(此处可以进行一些清除工作)

End Sub

在必要的时候,可以调用这个方法来确保内存清除工作的进行。

6.如何使用访问类型

在很多情况下,都会将编写好的类提供给别人,供他们使用它提供的功能。例如,他们可以调用类的一个方法或者访问其中的一个域。面向对象编程的一个最大的好处是开发人员可以方便地控制对类成员的访问,这意味着可以完全控制想让别人使用的部分。可以使一个方法可以被别的开发人员使用,也可以使一个类成员只能在该类中被访问。

在VB.NET中,访问是分等级的。下面我们来讨论这些等级。

①Public:Public类成员没有访问限制。在一个类成员前面添加Public关键字就使得它可以被随意访问。例如,Person类中的PrintSalary方法就是一个public方法,可以从任何地方对它进行访问。

②Private:秘密的类成员只能被该类内部的其他成员访问。使用Private关键字就可以使一个类成员成为秘密的。

③Protected:被保护的类成员只能被该类的派生类和该类本身内部进行访问。使用Protected关键字就可以使类成员成为被保护的类成员。

④Friend:具有friend级访问限制的类成员只能在定义该类的程序内部使用,使用Friend关键字就能使类成员具有friend级访问限制。

⑤Protectedfriend:这是protected和friend两种访问类型的组合。这些不同的访问类型使面向对象编程具有了信息隐藏能力。也就是说,可以使用这些访问类型来保护不愿意让别人访问的信息。

7.如何使用静态成员

再来看看Person类,也许读者会对我们没有将System.Console类实例化就使用它的Write方法有点不理解,为什么可以这样做呢?因为在面向对象编程语言中,有一种被称作静态成员的特殊的类成员VB.NET,也有静态成员这一概念。无须对一个对象实例化就可以使用其中的静态成员。例如,下面的代码列表中,SalaryLevel类中就只包含有静态的域。

类中的静态成员:

Class SalaryLevel

Public Shared Level1 As integer=1

Public Shared Level2 As integer=2

Public Shared Level3 As integer=3

Public Shared Level4 As integer=4

Public Shared Level5 As integer=5

End Class

可以这样使用此类:

Class Person

Dim yearlyBonus As integer=10

Public Sub PrintSalary()

’使用SalaryLevel类的静态域向Console输出工资额

Console.Write(SalaryLevel.Level4)

End Sub

Public Shared Sub Main()

Dim person As Person

person=New Person()

person.PrintSalary()

End Sub

End Class

在Person类的PrintSalary方法中,可以在不首先创建SalaryLevel类变量的情况下使用其中的静态域Level4。不属于静态成员的类成员被称作实例成员。

静态类:在类的前面加上Shared关键字可以使这个类变成一个静态类,静态类无须进行实例化就可以使用它里面的方法和变量。

8.如何使用全局变量

对于共享变量,另外一个通常的应用是提供了全局变量的类型。给定一个Public作用域的共享变量:

Public Class TheClass

Public Shared MyGlobal As Integer

End Class

我们可以在客户代码中使用这个变量。

TheClass.MyGlobal+=5

这个变量在我们应用程序的任何地方都是有效的,它提供了一个很好的机制在组件、类、模块等之间来共享数值。

6.3.5如何进行继承

当通过继承来创建一个子类的时候,新类就可以从父类中得到所有的Public(公共)和Friend(友好)方法、属性和变量。如果你在父类中声明一个Private(私有)的方法、属性和变量,那么在新的子类中就不能得到父类中这个私有的方法、属性和变量。当然也有个例外,就是New方法。构造函数方法必须在每一个子类中重新编写。继承是扩展类的一种特性。如果需要完成一些功能,当然可以创建一个新类,但如果别人所创建的类可以提供一部分用户所需要的功能,就可以创建一个扩充了原有类的新类。创建的类可以称为子类或派生类,原来的类可以被称为父类或基类。在VB.NET中,一个类只能继承一个父类,多类继承在VB.NET中是不允许的。在类名后加一个冒号,后面再加上关键字Inherits和父类的名字就可以完成对类的继承。例如,下面的代码就通过扩充Person类创建了一个被称为Employee的新类:

扩充类:

Imports System

Class Person

Dim salary As integer=10

Dim yearlyBonus As integer=10

Public Sub PrintSalary()

Console.Write(salary)

End Sub

End Class

Class Employee: Inherits Person

End Class

现在,就可以初始化一个Employee对象,并使用Person中的成员。如下面的代码所示:

初始化Employee对象

Class Person

Public salary As integer=10

Public yearlyBonus As integer=10

Public Sub PrintSalary()

Console.Write(salary)

End Sub

End Class

Class Employee: Inherits Person

End Class

Module Module1

Public Sub Main()

Dim employee As Employee

employee=New Employee()

employee.PrintSalary()

End Sub

End Module

下面代码演示了如何通过编写一个新的PrintBonus方法来扩充Employee类别的方法。

在子类中添加新的方法:

Class Employee: Inherits Person

Public Sub PrintBonus()

Console.Write(yearlyBonus)

End Sub

End Class

必须注意成员可访问性限制的使用。例如,如果使yearlyBonus域具有private属性,就不能被Employee类访问。继承是面向对象编程中常用的方法。实际上,.NET Framework类库中就有许多由继承其他类得到的类。例如,Windows.Forms名字空间中的Button类就是ButtonBase类的一个子类,而ButtonBase类本身又是Control类的一个子类。

所有的类最终都是System.Object类的子类,在.NET Framework类库中,System.Object类被称为根或超级类。

下面ClassThree就是不可继承的类:

NotInheritable Class ClassThree

End Class

如果扩充这个类就会引起编译错误。为什么要使类不可继承呢?一个原因是不希望别人扩充我们的类,另一个原因是不可扩充的类产生的代码运行速度更快。尽管这样,还是应该小心地使用不可继承的类,因为它不符合面向对象编程的初衷,只有在100%地肯定不扩充这个类时,才能使它不可继承。在有些面向对象编程语言中,这些类也被称作最终的类。

如果想让子类中继承父类的方法改变,可以先声明父类的方法是Overidable。然后在子类中用关键字Override把此方法进行重写。在类或控件的继承中,子类或子控件封装了父类的所有函数,其中包括事件处理程序。

如何使用事件:

Public Class EventSource’声明一个事件

Public Event LogonCompleted(ByVal UserName As String)

Sub CauseEvent()’激发事件

RaiseEvent LogonCompleted(”AustinSteele”)

End Sub

End Class

引发事件的类是事件源,而处理事件的方法是事件处理程序。事件源对它生成的事件可以具有多个处理程序。当类引发事件时,将在每一个被选择用来处理该对象实例的事件的类上引发该事件。