封裝

封裝隱藏了客戶端程式碼的實現細節

處理將對 QueryClose 示例演示封裝:形式都有一個核取方塊控制,但它的客戶端程式碼不直接合作 -核取方塊是一個實現細節,什麼客戶端程式碼需要知道的是設定是否啟用。

當核取方塊值更改時,處理程式將分配一個私有欄位成員:

Private Type TView
    IsCancelled As Boolean
    SomeOtherSetting As Boolean
    'other properties skipped for brievety
End Type
Private this As TView

'...

Private Sub `SomeOtherSettingInput_Change()`
    this.SomeOtherSetting = `CBool(SomeOtherSettingInput.Value)`
End Sub

當客戶端程式碼想要讀取該值時,它不需要擔心核取方塊 - 而只是使用 SomeOtherSetting 屬性:

Public Property Get `SomeOtherSetting()` As Boolean
    SomeOtherSetting = this.SomeOtherSetting
End Property

SomeOtherSetting 屬性封裝了核取方塊’state; 客戶端程式碼不需要知道有一個核取方塊,只是有一個布林值的設定。通過封裝 Boolean 值,我們在核取方塊周圍新增了一個抽象層

使用介面來強制實現不變性

讓我們通過表單的模型**封裝在專用的類模組中來進一步推進。但是如果我們為 UserNameTimestamp 製作了一個 Public Property,我們將不得不暴露 Property Let 訪問器,使屬性變得可變,並且我們不希望客戶端程式碼能夠在設定後更改這些值。

抽象示例中的 CreateViewModel 函式返回一個 ISomeModel 類:這是我們的介面,它看起來像這樣:

Option Explicit

Public Property Get Timestamp() As Date
End Property

Public Property Get UserName() As String
End Property

Public Property Get AvailableItems() As Variant
End Property

Public Property Let AvailableItems(ByRef value As Variant)
End Property

Public Property Get SomeSetting() As String
End Property

Public Property Let SomeSetting(ByVal value As String)
End Property

Public Property Get SomeOtherSetting() As Boolean
End Property

Public Property Let SomeOtherSetting(ByVal value As Boolean)
End Property

請注意,TimestampUserName 屬性僅顯示 Property Get 訪問器。現在 SomeModel 類可以實現該介面:

Option Explicit
Implements ISomeModel

Private Type TModel
    Timestamp As Date
    UserName As String
    SomeSetting As String
    SomeOtherSetting As Boolean
    AvailableItems As Variant
End Type
Private this As TModel

Private Property Get ISomeModel_Timestamp() As Date
    ISomeModel_Timestamp = this.Timestamp
End Property

Private Property Get ISomeModel_UserName() As String
    ISomeModel_UserName = this.UserName
End Property

Private Property Get ISomeModel_AvailableItems() As Variant
    ISomeModel_AvailableItems = this.AvailableItems
End Property

Private Property Let ISomeModel_AvailableItems(ByRef value As Variant)
    this.AvailableItems = value
End Property

Private Property Get ISomeModel_SomeSetting() As String
    ISomeModel_SomeSetting = this.SomeSetting
End Property

Private Property Let ISomeModel_SomeSetting(ByVal value As String)
    this.SomeSetting = value
End Property

Private Property Get ISomeModel_SomeOtherSetting() As Boolean
    ISomeModel_SomeOtherSetting = this.SomeOtherSetting
End Property

Private Property Let ISomeModel_SomeOtherSetting(ByVal value As Boolean)
    this.SomeOtherSetting = value
End Property

Public Property Get Timestamp() As Date
    Timestamp = this.Timestamp
End Property

Public Property Let Timestamp(ByVal value As Date)
    this.Timestamp = value
End Property

Public Property Get UserName() As String
    UserName = this.UserName
End Property

Public Property Let UserName(ByVal value As String)
    this.UserName = value
End Property

Public Property Get AvailableItems() As Variant
    AvailableItems = this.AvailableItems
End Property

Public Property Let AvailableItems(ByRef value As Variant)
    this.AvailableItems = value
End Property

Public Property Get SomeSetting() As String
    SomeSetting = this.SomeSetting
End Property

Public Property Let SomeSetting(ByVal value As String)
    this.SomeSetting = value
End Property

Public Property Get SomeOtherSetting() As Boolean
    SomeOtherSetting = this.SomeOtherSetting
End Property

Public Property Let SomeOtherSetting(ByVal value As Boolean)
    this.SomeOtherSetting = value
End Property

介面成員都是 Private,並且必須實現介面的所有成員才能編譯程式碼。Public 成員不是介面的一部分,因此不會暴露於針對 ISomeModel 介面編寫的程式碼。

使用工廠方法模擬建構函式

使用 VB_PredeclaredId 屬性,我們可以使 SomeModel 類有一個預設例項,並編寫一個函式,類似於型別級(VB.NET 中的 Shared,C#中的 static)成員,客戶端程式碼可以呼叫而無需首先建立像我們在這裡做的一個例項:

Private Function `CreateViewModel()` As ISomeModel
    Dim result As ISomeModel
    Set result = SomeModel.Create(Now, Environ$("UserName"))
    result.AvailableItems = GetAvailableItems
    Set CreateViewModel = result
End Function

這個工廠方法分配從 ISomeModel 介面訪問時只讀的屬性值,這裡是 TimestampUserName

Public Function Create(ByVal pTimeStamp As Date, ByVal pUserName As String) As ISomeModel
    With New SomeModel
        .Timestamp = pTimeStamp
        .UserName = pUserName
        Set Create = .Self
    End With
End Function

Public Property Get Self() As ISomeModel
    Set Self = Me
End Property

現在我們可以對 ISomeModel 介面進行編碼,該介面將 TimestampUserName 作為只讀屬性公開,永遠不能重新分配(只要程式碼是針對介面編寫的)。