VB接口与抽象类.docx
《VB接口与抽象类.docx》由会员分享,可在线阅读,更多相关《VB接口与抽象类.docx(25页珍藏版)》请在冰豆网上搜索。
VB接口与抽象类
目录
VB接口的概念1
接口要点1
示例一:
IDisplayer2
示例二:
ISpeak8
示例三:
实现多态(Animal)10
示例四:
IEnumerator11
示例五:
Implements语句13
.NET抽象类13
创建VB.NET抽象类14
实际操作中使用VB.NET抽象类15
示例15
.NET接口和.NET抽象类的相同点和不同点16
相同点16
不同点16
.NET接口和.NET抽象类的规则与场合17
VB接口的概念
2006-09-2911:
12
谢谢'妖居"前辈写的文章,原文地址
只支持单继承的VB.NET为了解决多继承的问题,引入了接口的概念。
我们可以这样来为接口下一个定义:
接口就是指只包含虚成员的虚类。
1.虚类,表明了接口是不能够被直接实例化的。
也就是说,接口只是一个抽象概念。
比如我们说车可以跑,人可以跑,马可以跑。
我们可以看到实例化的车、人、马。
但是我们可以定义一个“会跑的物质”。
他可以是车,也可以使人、马,但是我们却不能说“这个东西就是一个会跑得物质,但是它并不是车、人或者马。
”
2.只包含虚成员,表明了接口只是说明了它具有什么样的功能,可以提供什么样的信息。
但是这些功能和信息究竟是什么,如何提供我们无法得知。
就像是“会跑的物质”,我们知道它可以跑,但是具体他怎么跑我们就不知道了。
之所以说接口可以部分替代多继承,就是因为VB.NET只允许一个类继承自另一个,且只能是这个类;但是一个类可以实现一个或多个接口。
由于接口不实现成员,只声名成员,所以也就不存在多继承的路径问题了。
接口要点
1、定义接口名,应按照惯例,将接口名的第一个字母命名为I,如上例中的ISpeak,这样做的目的是见名知义,原因是因为接口的英语单词是Interface;
2、由于接口中的成员签名必须在实现该接口的类中给出其具体实现,所以它们前面不用加访问级别修饰符(Public、Privated等);
3、类通过Implements关键字实现接口;
4、一个类要实现一个接口,就必须实现该接口中定义的所有成员签名;
5、一个类可以实现多个接口,方法是在接口名用“,”隔开,如ImplementsISpeak,IRun。
现在我们假定您已经知道了接口的声名以及相关的一些基本知识,我们来看看什么时候我们需要使用接口。
示例一:
IDisplayer
当我们面临一个问题,就是我们有一个功能,它需要操作不同的类的实例去完成一个目的相同的方法的时候,我们就可以把这些目的相同的方法作为接口来实现。
现在我们看看我们面临的问题。
目前我们手头有一些类,它们之间没有继承关系,但是这些类都可以被显示成字符串。
'图书类。
可以显示的是书名。
PublicClassBook
InheritsMedia
Privatem_NameAsString
PublicFunctionDisplay()AsString
Returnm_Name
EndFunction
EndClass
'LCD显示器类,可以显示的是显示器屏幕上面的内容。
PublicClassLCD
InheritsComputerService
Privatem_DisplayCommentAsString
PublicFunctionDisplay()AsString
Returnm_DisplayComment
EndFunction
EndClass
'用户类,显示的是全名(姓+名)。
PublicClassUser
InheritsPerson
Privatem_FirstName,m_LastNameAsString
PublicFunctionDisplay()AsString
Returnm_FirstName&"."&m_LastName
EndFunction
EndClass
现在我们希望我们的程序(函数)能够把这些显示内容通过Console输出到控制台上面。
由于它们不是同一个类继承的,所以我么现在有两种选择:
1.为每一个类做一个函数,分别对应着一个类的显示函数:
代码复杂,而且如果新加入了别的类,我们不得不在做一个函数。
2.使用一个函数,用Object代替这些类,使用晚期绑定实现:
不安全,如果开发者传递了一个没有相应方法的实例进取就会引发异常。
现在我们使用接口看看。
接口是不依照类的继承关系存在的,所以我们需要首先定义一个接口。
它包含了一个Display方法。
这说明了符合这个接口的所有实例必然有这样的一个方法,名字叫做Display,没有参数,返回字符串:
PublicInterfaceIDisplayer
FunctionDisplay()AsString
EndInterface
这个Display方法只是一个虚函数,没有内容,因为我们并不知道他们应该怎么被Display。
但是我们能够保证,他可以被Display,这样就足够了。
现在我们使用这个接口来封装我们的三个类。
让他们实现这个接口,实现的同时我们也必须实现接口里面的所有虚程序。
这相当于告诉编译器,我的类符合接口规定的功能,我能Display,我来告诉你怎样Display。
'图书类。
可以显示的是书名。
PublicClassBook
InheritsMedia
ImplementsIDisplayer
Privatem_NameAsString
PublicFunctionDisplay()AsStringImplementsIDisplayer.Display
Returnm_Name
EndFunction
EndClass
'LCD显示器类,可以显示的是显示器屏幕上面的内容。
PublicClassLCD
InheritsComputerService
ImplementsIDisplayer
Privatem_DisplayCommentAsString
PublicFunctionDisplay()AsStringImplementsIDisplayer.Display
Returnm_DisplayComment
EndFunction
EndClass
'用户类,显示的是全名(姓+名)。
PublicClassUser
InheritsPerson
ImplementsIDisplayer
Privatem_FirstName,m_LastNameAsString
PublicFunctionDisplay()AsStringImplementsIDisplayer.Display
Returnm_FirstName&"."&m_LastName
EndFunction
EndClass
'显示函数。
PublicSubDisplay(ByValidrAsIDisplayer)
MsgBox(idr.Display)
EndSub
我们使用了参数idr,这个参数的类型是一个接口IDisplayer。
我们使用接口可以像使用类一样。
实际上我们传递进来的是实现了这个接口的某个类的实例,但是这并不是我们关心的。
我们只要知道,这个类可以Display就足够了。
所以我么只需要直接调用接口函数Display,就可以调用到这个接口实例里面的Display函数。
他肯定存在,因为他实现了接口。
如果不存在,编译器就会报错的。
这样我们就可以在不知道实例类型的情况下使用方法了,而且它很安全。
如果我们需要加入一个新的类,比如是Company类,我们只要让他也实现了这个接口,就可以直接适用这个函数了。
接口也允许继承,而且允许多继承,但是接口只能从接口继承。
比如我们的IDisplayer接口继承了两个.NET的接口。
PublicInterfaceIDisplayer
InheritsICloneable,IComparer
FunctionDisplay()AsString
EndInterface
一个是ICloneable,他表示我们的接口支持复制(克隆);另一个是IComparer,他表示我们的接口支持比较。
现在我们这三个类就出现了编译错误,因为我们现在只实现了IDisplayer的虚函数Display,基接口(ICloneable,IComparer)的虚函数(Compare,Clone())我们还没有实现。
所以我们的还必须实现基接口的虚成员。
我们以Book为例,需要稍加改动:
'图书类。
可以显示的是书名。
PublicClassBook
InheritsMedia
ImplementsIDisplayer
Privatem_NameAsString
PublicSubNew(ByValNameAsString)
m_Name=Name
EndSub
PublicFunctionDisplay1()AsStringImplementsIDisplayer.Display
Returnm_Name
EndFunction
PublicFunctionCompare(ByValxAsObject,ByValyAsObject)AsIntegerImplementsSystem.Collections.IComparer.Compare
Dimbx,byAsBook
IfTypeOfxIsBookAndAlsoTypeOfyIsBookThen
bx=CType(x,Book)
by=CType(y,Book)
ReturnString.Compare(bx.m_Name,by.m_Name)
EndIf
EndFunction
PublicFunctionClone()AsObjectImplementsSystem.ICloneable.Clone
ReturnNewBook(m_Name)
EndFunction
EndClass
图书类实际上包含了三个接口:
IDisplayer、ICloneable和IComparer。
但是我们使用的时候,ICloneable和IComparer接口不会出现,它的函数会被当作IDisplayer来实现。
PublicSubDisplay(ByValidrAsIDisplayer)
MsgBox(idr.Display)
DimoAsObject=idr.Clone
EndSub
当我们发现一些毫不相干的类,却有一个共同的操作,他的参数和返回值一致,而我们恰恰要在某一个(或几个)地方频繁的使用的时候,我们不妨将这些相同的部分用接口实现。
但是前提条件是这些操作来设计逻辑来讲却是属于相同的操作。
不要为了使用接口而使用它。
以下为完整代码:
PublicInterfaceIDisplayer
InheritsICloneable,IComparer'此二接口在命名空间System.Collections下
FunctionDisplay()AsString'表明接口IDisplayer中有函数Display(),此函数具体内容在每个类中不同。
EndInterface
PublicClassMedia
'[statement]
EndClass
PublicClassComputerService
'[statement]
EndClass
PublicClassPerson
'[statement]
EndClass
'图书类。
可以显示的是书名。
PublicClassBook
InheritsMedia
ImplementsIDisplayer
Privatem_NameAsString
PublicFunctionDisplay()AsStringImplementsIDisplayer.Display'接口中函数的具体形式
Returnm_Name
EndFunction
PublicSubNew(ByValNameAsString)
m_Name=Name
EndSub
PublicFunctionCompare(ByValxAsObject,ByValyAsObject)AsIntegerImplementsSystem.Collections.IComparer.Compare
Dimbx,byAsBook
IfTypeOfxIsBookAndAlsoTypeOfyIsBookThen
bx=CType(x,Book)
by=CType(y,Book)
ReturnString.Compare(bx.m_Name,by.m_Name)
EndIf
EndFunction
PublicFunctionClone()AsObjectImplementsSystem.ICloneable.Clone
ReturnNewBook(m_Name)
EndFunction
EndClass
'LCD显示器类,可以显示的是显示器屏幕上面的内容。
PublicClassLCD
InheritsComputerService
ImplementsIDisplayer
Privatem_DisplayCommentAsString
PublicFunctionDisplay()AsStringImplementsIDisplayer.Display
Returnm_DisplayComment
EndFunction
PublicSubNew(ByValNameAsString)
m_DisplayComment=Name
EndSub
PublicFunctionCompare(ByValxAsObject,ByValyAsObject)AsIntegerImplementsSystem.Collections.IComparer.Compare
Dimbx,byAsLCD
IfTypeOfxIsLCDAndAlsoTypeOfyIsBookThen
bx=CType(x,LCD)
by=CType(y,LCD)
ReturnString.Compare(bx.m_DisplayComment,by.m_DisplayComment)
EndIf
EndFunction
PublicFunctionClone()AsObjectImplementsSystem.ICloneable.Clone
ReturnNewLCD(m_DisplayComment)
EndFunction
EndClass
'用户类,显示的是全名(姓+名)。
PublicClassUser
InheritsPerson
ImplementsIDisplayer
Privatem_FirstName,m_LastNameAsString
PrivatefullnameAsString
PublicFunctionDisplay()AsStringImplementsIDisplayer.Display
fullname=m_FirstName&"."&m_LastName
Returnfullname
EndFunction
PublicSubNew(ByValNameAsString)
fullname=Name
EndSub
PublicFunctionCompare(ByValxAsObject,ByValyAsObject)AsIntegerImplementsSystem.Collections.IComparer.Compare
Dimbx,byAsUser
IfTypeOfxIsUserAndAlsoTypeOfyIsUserThen
bx=CType(x,User)
by=CType(y,User)
ReturnString.Compare(bx.fullname,by.fullname)
EndIf
EndFunction
PublicFunctionClone()AsObjectImplementsSystem.ICloneable.Clone
ReturnNewUser(fullname)
EndFunction
EndClass
示例二:
ISpeak
本文提供的VB.NET接口范例希望能为读者建立起对接口一个初步的、正确的认识。
本例定义了一个名为ISpeak的接口,其中包括了三个签名。
由于接口是代表一种约定或者说是一种规则,它并不包含这种约定或者规则的具体实现。
所以,我们只需要在接口中定义签名即可。
在该接口中,包括了三个成员签名,它们分别代表了属性、方法以及函数。
接下来,我又定义了三个类,分别是Baby、Children和Adlut,这个三类都实现了上述接口。
并且,在每个类实现接口的成员时,都给出了具体的实现。
来看代码:
'定义一个接口
PublicInterfaceISpeak
'仅定义签名,不包含任何实现
ReadOnlyPropertyCanSpeak()AsBoolean'属性
SubSpeak()'方法
FunctionGetSpeakLevel()AsSpeakLevelEnum'函数
EndInterface
'说话水平枚举
PublicEnumSpeakLevelEnum
Bad'很差
Ordinary'一般
Fluent'流利
EndEnum
PublicClassBaby:
ImplementsISpeak'通过Implements关键字实现接口
'以下是实现该接口的所有成员
PublicReadOnlyPropertyCanSpeak()AsBooleanImplementsISpeak.CanSpeak
Get
ReturnFalse
EndGet
EndProperty
PublicFunctionGetSpeakLevel()AsSpeakLevelEnumImplementsISpeak.GetSpeakLevel
ReturnSpeakLevelEnum.Bad
EndFunction
PublicSubSpeak()ImplementsISpeak.Speak
Console.WriteLine("(旁白):
他是一个婴儿,还不会说话。
")
EndSub
EndClass
PublicClassChildren:
ImplementsISpeak
PublicReadOnlyPropertyCanSpeak()AsBooleanImplementsISpeak.CanSpeak
Get
ReturnTrue
EndGet
EndProperty
PublicFunctionGetSpeakLevel()AsSpeakLevelEnumImplementsISpeak.GetSpeakLevel
ReturnSpeakLevelEnum.Ordinary
EndFunction
PublicSubSpeak()ImplementsISpeak.Speak
Console.WriteLine("哈哈,我是一个快乐的孩子!
")
EndSub
EndClass
PublicClassAdult:
ImplementsISpeak
PublicReadOnlyPropertyCanSpeak()AsBooleanImplementsISpeak.CanSpeak
Get
ReturnTrue
EndGet
EndProperty
PublicFunctionGetSpeakLevel()AsSpeakLevelEnumImplementsISpeak.GetSpeakLevel
ReturnSpeakLevelEnum.Fluent
EndFunction
PublicSubmySpeak()ImplementsISpeak.Speak
Console.WriteLine("OK,我是成年人了,不但能流利地说母语,还会说外语。
")
EndSub
EndClass
'程序入口点
PublicClassAppStart
SharedSubMain()
Dimperson1AsNewBaby
Dimperson2AsNewChildren
Dimperson3AsNewAdult
person1.Speak()
person2.Speak()
person3.mySpeak()
Ifperson2.GetSpeakLevel>SpeakLevelEnum.BadThen
Console.WriteLine("Person2的说话水平不算很差")
EndIf
Ifperson1.CanSpeakThen
Console.WriteLine("Person1会说话")
Else
Console.WriteLine("Person1不会说话")
EndIf
Console.Read()
EndSub
EndClass
PublicClassForm1
PrivateSubButton1_Click(senderAsObject,eAsEventArgs)HandlesButton1.Click
AppStart.Main()
EndSub
EndClass
在VS2005/2008中建立一个“控制台项目”项目,将默认的Module1.vb删除,在该项目中添加一个类,将上述代码复制到这个类中覆盖原有内容,即可运行调试。
示例三:
实现多态(Animal)
VB.NET接口实现多态,能够通过使用多接口,用户可以在不中断运行代码的情况下,允许运行多种软件的系统组件。
接口象类那样描述属性和方法,但是它和类不同的是,接口不能提供任何实现。
为了正确的操作VB.NET接口实现多态,用户需先建立一个接口,并且通过其他的几个类实现该接口。
用户可以用几乎相同的方法调用其他对象已经实现的方法。
下面这个例子就是VB.NET接口实现多态:
NamespacePolyNamespace
InterfaceAnimal
SubMove(ByRefDistanceAsDouble)
SubBite(ByValWhatAsObject)
EndInterface
ClassFlea
Implementsanimal
PublicSubbite(ByValWhatAsObject)ImplementsAnimal.Bite
'Bitesomething
EndSub
SubMove(ByRefDistanceAsDouble)ImplementsAnimal.Move
Distance=Distance+1
EndSub
EndClass
ClassDog
Implementsanimal
PublicSubbite(ByValWhatAsObject)ImplementsAnimal.Bite
'Bitesomething
EndSub
SubMove(ByR