1. 程式人生 > >淺談VB.NET中的介面

淺談VB.NET中的介面

只支援單繼承的VB.NET為了解決多繼承的問題,引入了介面的概念。我們可以這樣來為介面下一個定義:介面就是指只包含虛成員的虛類。<?XML:NAMESPACE PREFIX = O />

(1)虛類,表明了介面是不能夠被直接例項化的。也就是說,介面只是一個抽象概念。比如我們說車可以跑,人可以跑,馬可以跑。我們可以看到例項化的車、人、馬。但是我們可以定義一個“會跑的物質”。他可以是車,也可以使人、馬,但是我們卻不能說“這個東西就是一個會跑得物質,但是它並不是車、人或者馬。”

(2)只包含虛成員,表明了介面只是說明了它具有什麼樣的功能,可以提供什麼樣的資訊。但是這些功能和資訊究竟是什麼,如何提供我們無法得知。就像是“會跑的物質”,我們知道它可以跑,但是具體他怎麼跑我們就不知道了。

之所以說介面可以部分替代多繼承,就是因為VB.NET只允許一個類繼承自另一個,且只能是這個類;但是一個類可以實現一個或多個介面。由於介面不實現成員,只聲名成員,所以也就不存在多繼承的路徑問題了。

現在我們假定您已經知道了介面的聲名以及相關的一些基本知識,我們來看看什麼時候我們需要使用介面。

當我一個問題,就是我有一個功能,它需要操作不同的例去完成一個目的相同的方法的候,我就可以把些目的相同的方法作介面來實現在我看看我問題。目前我們手頭有一些類,它們之間沒有繼承關係,但是這些類都可以被顯示成字串。

'圖書類。可以顯示的是書名。

Public Class

Book

Inherits Media

Private m_Name As String

Public Function Display() As String

Return m_Name

End Function

End Class

'LCD顯示器類,可以顯示的是顯示器螢幕上面的內容。

Public Class LCD

Inherits ComputerService

Private m_DisplayComment As String

Public Function Display() As String

Return m_DisplayComment

End Function

End Class

'使用者類,顯示的是全名(姓 + 名)。

Public Class User

Inherits Person

Private m_FirstName, m_LastName As String

Public Function Display () As String

Return m_FirstName & "." & m_LastName

End Function

End Class

現在我們希望我們的程式(函式)能夠把這些顯示內容通過Console輸出到控制檯上面。由於它們不是同一個類繼承的,所以我麼現在有兩種選擇。

(1)為每一個類做一個函式,分別對應著一個類的顯示函式。

(2)使用一個函式,用Object代替這些類,使用晚期繫結實現。

現在看看這兩種做法的問題。

(1)程式碼複雜,而且如果新加入了別的類,我們不得不在做一個函式。

(2)不安全。如果開發者傳遞了一個沒有相應方法的例項進取就會引發異常。

現在我們使用介面看看。介面是不依照類的繼承關係存在的,所以我們需要首先定義一個介面。它包含了一個Display方法。這說明了符合這個介面的所有例項必然有這樣的一個方法,名字叫做Display,沒有引數,返回字串。

Public Interface IDisplayer

Function Display() As String

End Interface

這個Display方法只是一個虛擬函式,沒有內容,因為我們並不知道他們應該怎麼被Display。但是我們能夠保證,他可以被Display。這樣就足夠了。現在我們使用這個介面來封裝我們的三個類。讓他們實現這個介面,實現的同時我們也必須實現接口裡面的所有虛程式。這相當於告訴編譯器,我的類符合介面規定的功能,我能Display,我來告訴你怎樣Display

'圖書類。可以顯示的是書名。

Public Class Book

Inherits Media

Implements IDisplayer

Private m_Name As String

Public Function Display() As String Implements IDisplayer.Display

Return m_Name

End Function

End Class

' LCD顯示器類,可以顯示的是顯示器螢幕上面的內容。

Public Class LCD

Inherits ComputerService

Implements IDisplayer

Private m_DisplayComment As String

Public Function Display () As String Implements IDisplayer.Display

Return m_DisplayComment

End Function

End Class

'使用者類,顯示的是全名(姓 + 名)。

Public Class User

Inherits Person

Implements IDisplayer

Private m_FirstName, m_LastName As String

Public Function Display() As String Implements IDisplayer.Display

Return m_FirstName & "." & m_LastName

End Function

End Class

現在我們著手做我們的顯示函式。

Public Sub Display(ByVal idr As IDisplayer)

MsgBox(idr.Display)

End Sub

我們使用了引數idr,這個引數的型別是一個介面IDisplayer。我們使用介面可以像使用類一樣。實際上我們傳遞進來的是實現了這個介面的某個類的例項,但是這並不是我們關心的。我們只要知道,這個類可以Display就足夠了。所以我麼只需要直接呼叫介面函式Display,就可以呼叫到這個介面例項裡面的Display函式。他肯定存在,因為他實現了介面。如果不存在,編譯器就會報錯的。這樣我們就可以在不知道例項型別的情況下使用方法了,而且它很安全。

如果我們需要加入一個新的類,比如是Company類,我們只要讓他也實現了這個介面,就可以直接適用這個函數了。

介面也允許繼承,而且允許多繼承,但是介面只能從介面繼承。比如我們的IDisplayer介面繼承了兩個.NET的介面。

Public Interface IDisplayer

Inherits ICloneable, IComparer

Function Display() As String

End Interface

一個是ICloneable,他表示我們的介面支援複製(克隆);另一個是IComparer,他表示我們的介面支援比較。

現在我們這三個類就出現了編譯錯誤,因為我們現在只實現了IDisplayer的虛擬函式Display,基介面的虛擬函式我們還沒有實現。所以我們的還必須實現基介面的虛成員。我們以Book為例,需要稍加改動。

'圖書類。可以顯示的是書名。

Public Class Book

Inherits Media

Implements IDisplayer

Private m_Name As String

Public Sub New(ByVal Name As String)

m_Name = Name

End Sub

Public Function Display1() As String Implements IDisplayer.Display

Return m_Name

End Function

Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare

Dim bx, by As Book

If TypeOf x Is Book AndAlso TypeOf y Is Book Then

bx = CType(x, Book)

by = CType(y, Book)

Return String.Compare(bx.m_Name, by.m_Name)

End If

End Function

Public Function Clone() As Object Implements System.ICloneable.Clone

Return New Book(m_Name)

End Function

End Class

圖書類實際上包含了三個介面:IDisplayerICloneableIComparer。但是我們使用的時候,ICloneableIComparer介面不會出現,它的函式會被當作IDisplayer來實現。

Public Sub Display(ByVal idr As IDisplayer)

MsgBox(idr.Display)

Dim o As Object = idr.Clone

End Sub

當我們發現一些毫不相干的類,卻有一個共同的操作,他的引數和返回值一致,而我們恰恰要在某一個(或幾個)地方頻繁的使用的時候,我們不妨將這些相同的部分用介面實現。但是前提條件是這些操作來設計邏輯來講卻是屬於相同的操作。不要為了使用介面而使用它。