多型性
多型性是為不同的底層實現提供相同介面的能力
實現介面的能力允許完全將應用程式邏輯與 UI 或資料庫或此工作表或該工作表分離。
假設你有一個表單本身實現的 ISomeView
介面:
Option Explicit
Public Property Get IsCancelled() As Boolean
End Property
Public Property Get Model() As ISomeModel
End Property
Public Property Set Model(ByVal value As ISomeModel)
End Property
Public Sub Show()
End Sub
表單的程式碼隱藏可能如下所示:
Option Explicit
Implements ISomeView
Private Type TView
IsCancelled As Boolean
Model As ISomeModel
End Type
Private this As TView
Private Property Get ISomeView_IsCancelled() As Boolean
ISomeView_IsCancelled = this.IsCancelled
End Property
Private Property Get ISomeView_Model() As ISomeModel
Set ISomeView_Model = this.Model
End Property
Private Property Set ISomeView_Model(ByVal value As ISomeModel)
Set this.Model = value
End Property
Private Sub ISomeView_Show()
Me.Show vbModal
End Sub
Private Sub SomeOtherSettingInput_Change()
this.Model.SomeOtherSetting = CBool(SomeOtherSettingInput.Value)
End Sub
'...other event handlers...
Private Sub OkButton_Click()
Me.Hide
End Sub
Private Sub CancelButton_Click()
this.IsCancelled = True
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = VbQueryClose.vbFormControlMenu Then
Cancel = True
this.IsCancelled = True
Me.Hide
End If
End Sub
但是,沒有什麼禁止建立另一個實現 ISomeView
介面的類模組而不是使用者表單 - 這可能是一個 SomeViewMock
類:
Option Explicit
Implements ISomeView
Private Type TView
IsCancelled As Boolean
Model As ISomeModel
End Type
Private this As TView
Public Property Get IsCancelled() As Boolean
IsCancelled = this.IsCancelled
End Property
Public Property Let IsCancelled(ByVal value As Boolean)
this.IsCancelled = value
End Property
Private Property Get ISomeView_IsCancelled() As Boolean
ISomeView_IsCancelled = this.IsCancelled
End Property
Private Property Get ISomeView_Model() As ISomeModel
Set ISomeView_Model = this.Model
End Property
Private Property Set ISomeView_Model(ByVal value As ISomeModel)
Set this.Model = value
End Property
Private Sub ISomeView_Show()
'do nothing
End Sub
現在我們可以更改使用 UserForm
的程式碼並使其在 ISomeView
介面上工作,例如通過將表單作為引數提供而不是例項化它:
Public Sub DoSomething(ByVal view As ISomeView)
With view
Set .Model = CreateViewModel
.Show
If .IsCancelled Then Exit Sub
ProcessUserData .Model
End With
End Sub
因為 DoSomething
方法取決於的介面(即,上抽象 ),而不是一個具體的類 (例如一個特定的 UserForm
),我們可以寫出一個自動化單元測試,以確保當 view.IsCancelled
是 True
ProcessUserData
不執行,通過使我們的測試建立一個 SomeViewMock
例項,將其 IsCancelled
屬性設定為 True
,並將其傳遞給 DoSomething
。
可測試程式碼取決於抽象
可以在 VBA 中編寫單元測試,有些外掛甚至可以將它整合到 IDE 中。但是當程式碼與工作表,資料庫,表單或檔案系統緊密耦合時,單元測試開始需要實際的工作表,資料庫,表單或檔案系統 - 而這些依賴性是新的失控失敗這點可測試的程式碼應隔離,從而使單元測試並不需要一個實際的工作表,資料庫,表格或檔案系統。
通過編寫針對介面的程式碼,以允許測試程式碼注入存根/模擬實現的方式(如上面的 SomeViewMock
示例),你可以在受控環境中編寫測試,並模擬 42 箇中的每一個可能發生的情況。表單資料上的使用者互動的排列,甚至沒有一次顯示錶單並手動單擊表單控制元件。