Visual Basic OOP Part 2 -- 封裝、繼承、多型

物件導向程式設計三大元素

  • 「封裝」指的是將一組相關的屬性、方法和其他成員,視為單一單位物件
  • 「繼承」則是描述依據現有類別來建立新類別的能力
  • 「多型」指的是您可以有多個交替使用的類別,即使每個類別是以不同的方式來實作相同的屬性或方法。

封裝, Encapsulation

當你寫下一段「Dim Name AS String = "KKBruce is handsome."」的程式碼之後,你知道String類別總共有多少屬性、方法?還有擴充方法?如果這些屬性、方法、擴充方法全部要你手動實作,我想光一個String類別,就能把你搞瘋了。

而封裝,就幫我們把所有相關實作(例如,字串相關功能)整理起來成為一個一個的類別(Class)。所以當我們建立此類別的執行個體(Name 物件)時,就能得到String類別所有的屬性、方法。我們能透過「Name.Length()」得知此字串的長度,透過「Name.IndexOf("Bruce")」找尋字串出現的位置。

透過封裝,你不用重覆造輪子,除非你有需求,或是你有信自能寫出比各種Framework所封裝類別更棒的類別庫,不然像.NET Framework所封裝的類別庫,應該可以解決你決大部分的需求。當然,我們還是有機會自己動手設計一些自己的類別,例如在ASP.NET MVC中,你就整天與Class相處。封裝還有一個好處,可以讓你隱藏整個的實作細節,這種作法稱為「資料隱藏」(Data Hiding)。

你不知道「Name.Length()」或「Name.IndexOf("Bruce")」是如何實作的,你只管用,只管結果。那這些類別的修改、變更「你或使用者」完全不用管,舉個例子,System.Text.StringBuilder 類別MISLab200測試的結果,在Visual Studio 2005與Visual Studio 2008進行比較,Visual Studio 2008快了5.45倍,也就是快了545%。如果你跟我說此類別完全沒有改寫,我是不太相信,但他們改寫了什麼,讓效能大幅提升,你不知道,我也不知道,但結果是一樣的。

所以,不管是使用別人封裝好的類別,還是你封裝給別人用的類別,重點有二:
  1. 不用重覆造輪子
  2. 資料隱藏

Public Class Student

    ' 建構式
    Sub New()
        _name = "無名氏"
        _Id = "S2010000000"
    End Sub

    ' 成員
    Private _name As String
    Private _id As String

    ' 屬性
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(value As String)
            _name = value
        End Set
    End Property
    Public Property Id() As String
        Get
            Return _id
        End Get
        Set(value As String)
            _id = value
        End Set
    End Property

    ' 方法
    Public Function GetResults(id As String) As DataSet
        ' 實作方法
    End Function

    Public Sub SetClass(id As String)
        ' 實作方法
    End Sub
End Class

以Class為單位來封裝「建構式、成員、屬性、方法」,記得,不管Class怎麼寫,就是寫這四個東西。

繼承, Inheritance

當類別越寫來越多時,你就能發現,有些類別有著「上下關係」,或者我想要改寫或擴充類別,但此類別已經被引用、使用至多處,直接的修改有其風險,這時我們就很適合使用繼承。繼承關係有可能邊寫邊發現,邊寫邊發現,一般我們會使用抽象類別,也可能是一開始就規劃出來,一般我們會使用介面。抽象類別和介面的使用時機,我已經在介紹過了。

例如,學校有老師、有學生,所以你會有Class Teacher及Class Student,但你能發現他們都有共同的性質,他們都是人,有名、有姓、有性別、有生日…所以我們就可以透過另一個類別Class Person來集中這些共有的性質,然後讓Class Teacher及Class Student來繼承Class Person的這些性質。

被繼承的類別稱為「基底類別」(Base Class),而繼承的類別即稱為「衍生類別」(Derived Class)。另.NET Framework的語言不支援多重繼承,也就是說,您只能為衍生類別指定一個基底類別。

Public Class Person
    ' 共同屬性
    Property FirstName() As String
    Property LastName() As String
    Property Sexy() As Boolean
    Property Birthday() As DateTime

    ' 共同方法
    Public Overridable Function Age() As String
        Return (Now.Year - _Birthday.Year + 1).ToString()
    End Function
End Class

Public Class Teacher
    Inherits Person

    ' 擴充或改寫基底類別
    Public Overrides Function ToString() As String
        Return "Hello, My Name is " & MyBase.FirstName & MyBase.LastName & _
               "I'm your teacher."
    End Function
End Class

Public Class Student
    Inherits Person

    ' 擴充或改寫基底類別
    Public Overrides Function ToString() As String
        Return "Hello, My Name is " & MyBase.FirstName & MyBase.LastName & _
               ", " & MyBase.Age() & "yeas ago."
    End Function
End Class

透過繼承,我們能適當的切割類別,能在衍生類別中重複使用擴充修改基底類別中定義的行為,又不破壞原先基底類別設計。而另外抽象類別及介面的使用,又是另一門學問稱「Design Patterrns/設計樣式/設計模式」。

多型, Polymorphism

多型又稱「同名異式」,也就是說,它能提供「具有不同功能名稱完全相同之方法或屬性」。


經Allen指點,我放錯範例子,以下範例為「多載」。

多載


System.String類別為例,它提供了8種同名稱,但依照你傳入參數不同,而有不作用的的建構式。


另外常用的方法,如Split(),也提供了6種,同名稱方法,但依照傳入參數不同而不同功能的方法。


這樣我們就很好理解多型多載。多型多載就是依型別的不同,即可找到對該的方法。這種的好處是,我們不必為相同方法之不同型別去進行無意義的命名,例如,Split_Char()、Split_CharInt32()、Split_Char_StrOpt()…。多型多載讓我們不管在使用方法或實作相關程式碼都降低複雜度。

封裝+繼承+多型=物件導向程式設計

由封裝、繼承、多型三者,架構出一整個物件導向程式設計,當然,每個部分還可以細切出很多理論細節,例如,多型還可以細切出「由繼承實作多型」或「由介面實作多型」,不過這不是我們目前討論的重點,我們先清楚封裝,封裝了什麼東西;繼承,.NET Framework只能單向繼承,形成一個Tree架構;多型,提供同一名稱不同實作功能。

清楚了,我們就接下去談千古話題:「類別與物件」。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。