1. 程式人生 > >VB.net學習筆記(十三)抽象類、多介面

VB.net學習筆記(十三)抽象類、多介面

向美術教師交作業時,一位學生只交了一張白紙。 
老師問:”畫呢?” 
學生答:”這兒?”他指著白紙說。 
老師:”你畫的是什麼?” 
學生:”牛吃草。” 
老師:”草呢?” 
學生:”牛吃光了。” 
老師:”牛呢?” 
學生:”草吃光了,牛還站在那裡幹什麼?”

一、抽象基類

       正如有個好爹可以少奮鬥二十一樣,父類本身是非常有用的,可以進行例項化,也可以不能例項化,做個樣子,好處很大。

      1、MustInheit

       基類可例項化,但也可以不例項化(或者禁止建立該類的物件),這時,只能建立子類,以及子類的物件。

       可以用MustInherit來指明該基類不能建立物件。

       注意:這不表示不能宣告基類(如下例Person)型別的變數,只是不能用New Peron來建立物件。

                   同時在這個時候,我們還可繼續使用共享辦法(因為它只屬於類,不屬於物件)

       2、MustOveride

       指明只能由子類重寫的方法(sub,funciton,property),此類方法只有方法頭,而無具體的實現程式碼。因此不能建立物件。

       故:  類中含有MustOveride時,此類必須由MustInherit進行宣告。即:

       只能在屬性和過程宣告語句中使用 MustOverride。 指定 MustOverride 的屬性或過程必須是類的成員,並且該類必須標

       記為 MustInherit。       

Public MustInherit Class Person '只能被繼承
    Private mName As String
    Private mBirthDate As Date
    Private mID As String

    Public Event NameChanged(ByVal newName As String)
    Public Event DataChanged(ByVal field As String, ByVal newValue As Object)

    Public MustOverride Function LifeExpectancy() As Integer '無實現程式碼,只能被子類重寫

    '......

End Class
        上面宣告Mustoveride的函式LifeExpectancy只有方法頭,無實現程式碼,此類方法也稱“抽象方法”或“純虛擬函式”
       

         任何繼承此類的子類,必須重寫這些抽象方法,否則將產生語法錯誤,子類也不會編譯。

          故在子類中新增:

'=======子類Employee中重寫基類的純虛擬函式===============
    Public Overrides Function LifeExpectancy() As Integer
        Return 90
    End Function

         

          3、抽象基類

           MustInherit及MustOverride同時出現該類時,此類被稱為抽象基類。或者說:含有抽象方法的類叫抽象基類。

           抽象基類很有用,可以前期只架上抽象基類這個架子,每個子類根據自己情況進行重寫適合自己的方法。

          注意的是,此時子類都必須有抽象方法的實現程式碼,否則出錯。

Public MustInherit Class AbstractBaseClass
    Public MustOverride Sub DoSomething()
    Public MustOverride Sub DoOtherSomething()
End Class

'介面
Public Interface IAbstractBaseClass
    Sub DoSomething()
    Sub DoOtherSomething()
End Interface

         某些方面,抽象基類與Interface介面概念相似,上面介面IAbstractBaseClass,在實現這介面的類中也必須有其內兩個方法

         的實現程式碼,否則一樣也會出錯。

        4、禁止繼承

         上面是“只能繼承”中建立物件。

         下面是“禁止繼承”,用NotIneritable來說明此類,不準再進行繼承,到此為止!

Public NotInheritable Class officeEmployee '指定基不再做基類(即不再向下派生)
            不能被繼承的類有時被稱為“密封”類

二、多介面

       介面,如同外交家一樣,可以與外界進行交流。

       VB.net中,物件可以有一個或多個介面。所有物件都有一個主介面或本地介面,介面由用Public宣告的方法、屬性、事件、欄位。

       除本地介面外,物件還可以使用Implements來實現輔助介面。

     1、物件介面

      類中除Private宣告的外都可作本地介面。例:

    '方法作為介面
    Public Sub AMethod()

    End Sub

    '屬性作為介面
    Public Property AProperty() As String

    End Property

    'Event事件作介面
    Public Event AEvent()

    '變數作介面
    Public AInteger As Integer

         注意:上面無實現程式碼,因為介面只在於架子的宣告,其內的實現程式碼並不是介面的一部分。這是重要的區別!

                      因為將介面與實現程式碼區分是面向物件程式設計的核心內容。

        使用本地介面

        一旦聲明瞭本地介面,就可在物件中用這些介面與外界產生交流。下面類中Pulbic方法,其物件就可直接用它與外界發生聯絡。

'============類的本地介面=========
Public Class TheClass
    Public Sub DoSomething()
       '.....
    End Sub

    Public Sub DoOtherSomething()
      '.......
    End Sub
End Class

 '==========主程式中使用這兩個介面========
        Dim myObject As New TheClass
        myObject.DoSomething()
        myObject.DoOtherSomething()


        2、輔助介面

         在設計上,只有同類的物件才有相同的本地介面,這有很大的限制。

          如果把一組不同的物件,它們本地介面各不同,處理起來就麻煩了。

          比如,對於產品 、顧客、發票三類物件,不具有自然的繼承關係,但是,我們需要列印這三個資訊,於是,

         產生了另一個概念“輔助介面”,也就平時說的介面,通過這個介面,使三者均可列印。

         介面Interface是同Class,Modul一樣是同一級別的概念,它象抽象方法一樣並不具有實現程式碼,實現程式碼都在使用介面

         的類中。這樣使用介面時,不必管是不是同一型別物件,均可正常執行。

        (1)定義介面

           用Interface來定義一個介面,通過新增模組方式,在模組外部新增介面程式碼:

Public Interface IPrintableObject '介面定義(與Class,Module平級)內部作用域相同
    Function Label(ByVal index As Integer) As String '故其前無Public,friend等限定
    Function Value(ByVal index As Integer) As String
    ReadOnly Property Count() As Integer
End Interface

Module Interfaces

End Module

            介面定義包含在 Interface 和 End Interface 語句內。 

            在 Interface 語句後面,可以選擇新增列出一個或多個被繼承介面的 Inherits 語句。  即介面可以繼承。

            在宣告中,Inherits 語句必須出現在除註釋外的所有其他語句之前。 

            介面定義中其餘的語句應該包括 Event、Sub、Function、Property、Interface、Class、Structure 和 Enum 語句。 

            介面不能包含任何實現程式碼或與實現程式碼關聯的語句,如 End Sub 或 End Property。

            在名稱空間中,預設情況下,介面語句為 Friend,但也可以顯式宣告為 Public 或 Friend。

            在類、模組、介面和結構中定義的介面預設為 Public,但也可以顯式宣告為 Public、Friend、Protected 或 Private。

            Shadows 關鍵字可應用於所有介面成員。 Overloads 關鍵字可應用於介面定義中宣告的 Sub、Function 和 Property 語句。

            此外,Property 語句可以具有 Default、ReadOnly 或 WriteOnly 修飾符。 不允許使用任何其他修飾符:Public、Private、

           Friend、Protected、Shared、Overrides、MustOverride 或 Overridable。

           介面是一個數據型別,類似於類或結構(Struction)。因為可以這樣定義這個型別的變數:

    Private printable As IPrintableObject

            但上面,都沒有實現的程式碼,實現程式碼都是在類中實現。所以介面是不能直接用New的。


           (2)使用介面

             使用者只須知道介面,不必瞭解物件內部細節,就可以使用不同的物件。

             窗體中新增方法:

    Public Sub PrintObject(obj As IPrintableObject)  '窗體內新增例程
        Dim index As Integer

        For index = 0 To obj.Count
            Debug.Write(obj.Label(index) & ": ")
            Debug.WriteLine(obj.Value(index))
        Next
    End Sub

           然後窗體中新增按鈕,並新增程式碼:

Private Sub ButtonPrint_Click(sender As Object,e As EventArgs) Handles ButtonPrint.Click
    Dim obj As New Employee()

    obj.EmployeeNumber = 123
    obj.BirthDate = #1/1/1980#
    obj.HireDate = #1/1/1996#
    PrintObject(obj)
End Sub

         點選執行,會提示錯誤:因為介面只是方法頭或事件頭,並沒有具體的實現程式碼。因此還要在類中新增實現的程式碼。        

         (3)實現介面

           任何類(除抽象基類)都可以使用Implements來實現介面。

           因為介面要用類的物件來傳遞,使得介面最後言之有物。而抽象基類是不能產生物件的,所以抽象基類是不能有介面的。

            加入Implements回車後,會自動把介面各方法或事件的架子新增到類中,我們只須在內加入實現程式碼。

            類中實現的方法、屬性等名稱,並不重要,重要的是引數的資料型別及返回值必須與介面定義的型別相匹配。

            實現程式碼如下:

'================Employee類中實現介面(連線到外部介面型別上)=========
    Implements IPrintableObject '這裡按回車後,自動新增Iprintableobject成員,來實現細節

    '為介面準備或要使用的欄位
    Private mLabels() As String = {"ID", "Age", "HireDate"}
    Private mBirthDate As Date
    Private mSalary As Double

    Public ReadOnly Property Count As Integer Implements IPrintableObject.Count
        Get
            Return UBound(mLabels)
        End Get
    End Property

    Private Function Label(index As Integer) As String Implements IPrintableObject.Label
        Return mLabels(index)
    End Function

    Public Function Value(index As Integer) As String Implements IPrintableObject.Value
        Select Case index
            Case 0
                Return CStr(EmployeeNumber)
            Case 1
                Return CStr(Age)
            Case Else
                Return Format(HireDate, "Short date")
        End Select
    End Function

         注意:可以看到實現方法等的後面有Implements IPrintableObject.Label,這類似於Handles,它也可以通過用逗號把

                     一個介面的多個方法聯絡到一個方法中,或者多個介面的方法聯絡到一個方法中。

                   (實際上就是把函式地址與外界聯絡了起來,這樣使用這個地址,自然就呼叫了不同物件中的方法)

            看一下整個介面的示意圖:


          (4)重用 通用的實現程式碼

            輔助介面,可以有幾個,幾個中可以同一個方法,這個方法就成了通用的方法。

            下面兩個介面有方法都聯絡到同一個方法Value(類Employe中)

'=========介面1,有Value=================
Public Interface IPrintableObject
    Function Label(ByVal index As Integer) As String
    Function Value(ByVal index As Integer) As String
    ReadOnly Property Count() As Integer
End Interface

'========介面2,有GetValue===============
Public Interface IVales
    Function GetValue(ByVal index As Integer) As String
End Interface


'=======Employee中兩介面,同時關聯到Value函式上(函式簽名與上面相同引數)===========
    Implements IPrintableObject
    Implements IVales

    Public Function Value(index As Integer) As String Implements IPrintableObject.Value, IVales.GetValue
        Select Case index
            Case 0
                Return CStr(EmployeeNumber)
            Case 1
                Return CStr(Age)
            Case Else
                Return Format(HireDate, "Short date")
        End Select
    End Function

          可以看到,其後用逗號表示,兩個介面都用到Value方法。

         (5)合併介面、繼承

          可以同時合併輔助介面和繼承在。

           當從一個實現介面的類繼承時,新的子類自動獲得的介面和基類的實現程式碼。

           如果指定基類方法可以重寫,則子類可以重寫這些方法。

           不僅重寫基類主介面的實現程式碼,而且也可以重寫介面的實現程式碼。

Public Overridable Function Value(ByVal index As Integer) As String  Implements IPrintableObject.Value, IValues.GetValue
           上面表示這個介面實現,是可以被重寫的。

          完整定義如下:

    Public Overridable Function Value(index As Integer) As String Implements IPrintableObject.Value, IVales.GetValue
        Select Case index
            Case 0
                Return CStr(EmployeeNumber)
            Case 1
                Return CStr(Age)
            Case Else
                Return Format(HireDate, "Short date")
        End Select
    End Function

          注意:由於上面是Public,因此它在主介面(本地介面)中也是有效的。

                     並且它還是兩個介面中的一部分,意味著可以被三種方式訪問。

            三種 方式訪問:

        Dim emp As New Employee("Andy")
        Dim printable As IPrintableObject = emp
        Dim values As IVales = emp

        Debug.WriteLine(emp.Value(0))
        Debug.WriteLine(printable.Value(0))
        Debug.WriteLine(values.GetValue(0))

           第一種:主介面(本地介面)

           第二種:IprintableObject介面訪問

           第三種:IValues介面訪問

           這樣三種介面合併於一身,都在Value這個方法上。


             要宣告介面方法的實現,可以使用任何在例項方法宣告上合法的特性(包括 Overloads、Overrides、Overridable、Public、Private、Protected、Friend、Protected Friend、MustOverride、Default 和 Static)。

             Shared 特性是不合法的,因為它定義類而不是例項方法。