使用 MVP 的 VBA 设置对话框 - 我需要模型吗?

i_s*_*nes 2 mvp vba

我一直在阅读 MVP(模型-视图-呈现器)及其变体(被动视图、监督视图)的许多示例,以尝试使我的解决方案在 VBA 中更加健壮(并且可重用)(在本例中使用 Excel 作为主机)实例)。我发现的问题是在 VBA 中找到好的、简单的示例,但对于我需要的(希望如此)简单的示例来说,这些示例并不是完全多余的。

我正在尝试创建一个“设置”对话框,将某些配置存储在工作表中(这是我的“存储库”)。

这是我的主要过程,由用户触发:

Private Sub ShowImportSelector()
    Dim importPresenter As DataImportPresenter
    Set importPresenter = New DataImportPresenter

    importPresenter.LoadConfig
    If importPresenter.Show = -1 Then Exit Sub
    importPresenter.SaveConfig

    ' begin processing...
    If (CStr([Settings.SelectedVersion].Value2) = "QQ") Then
       ' ...
    End If

End Sub
Run Code Online (Sandbox Code Playgroud)

这是我的“演示者”(这里我使用源范围名称和配置目标):

Option Explicit

Private m_importForm As FImport

Private Sub Class_Initialize()
    Set m_importForm = New FImport
End Sub

Public Sub LoadConfig()
    m_importForm.SetAvailableVersions "tblVERSION"
    m_importForm.SetAvailableSalesOrgs "tblSALESORG"
    m_importForm.SetAvailableCategories "tblCATEGORY"
    m_importForm.ToolName = "Forecast"
End Sub

Public Sub SaveConfig()
    [Settings.SelectedVersion].Value2 = m_importForm.SelectedVersion
    [Settings.SelectedSalesOrg].Value2 = m_importForm.SelectedSalesOrg
    [Settings.SelectedCategory].Value2 = m_importForm.SelectedCategory
End Sub

Public Function Show() As Integer
    m_importForm.Show vbModal
    Show = m_importForm.Result
End Function
Run Code Online (Sandbox Code Playgroud)

现在是“视图”(VBA 表单):

Option Explicit

Private m_selectedVersion As String
Private m_selectedSalesOrg As String
Private m_selectedCategory As String
Private m_toolName As String
Private m_dialogueResult As Long

Public Property Get ToolName() As String
    ToolName = m_toolName
End Property

Public Property Let ToolName(ByVal value As String)
    m_toolName = value
    ToolNameLabel.Caption = value
End Property

Public Property Get Result() As Long
    Result = m_dialogueResult
End Property

Public Property Get SelectedVersion() As String
    SelectedVersion = m_selectedVersion
End Property

Public Property Get SelectedSalesOrg() As String
    SelectedSalesOrg = m_selectedSalesOrg
End Property

Public Property Get SelectedCategory() As String
    SelectedCategory = m_selectedCategory
End Property

Public Sub SetAvailableVersions(ByVal value As String)
    VersionSelector.RowSource = value
End Sub

Public Sub SetAvailableSalesOrgs(ByVal value As String)
    SalesOrgSelector.RowSource = value
End Sub

Public Sub SetAvailableCategories(ByVal value As String)
    CategorySelector.RowSource = value
End Sub

Private Sub SaveSelections()
    m_selectedVersion = VersionSelector.value
    m_selectedSalesOrg = SalesOrgSelector.value
    m_selectedCategory = CategorySelector.value
End Sub

Private Sub CloseButton_Click()
    m_dialogueResult = -1
    Me.Hide
End Sub

Private Sub ImportButton_Click()
    SaveSelections
    m_dialogueResult = 0
    Me.Hide
End Sub
Run Code Online (Sandbox Code Playgroud)

此时,我对在上面添加模型方面可能采取的方向感到困惑 - 问题是:这个简单的示例是否需要这样做?

Mat*_*don 5

MVP 架构使代码更简洁,但更简洁的代码并不是 MVP 的主要目的;实现松耦合更高的内聚性可测试性

如果松散耦合的组件和可单元测试的逻辑不是必需的,那么成熟的 MVP 确实是大材小用,并且将“模型”暴露为“视图”上的属性绝对是足够好的,因为它已经有助于使您的“演示者”不需要关心表单控件。您将形式视为它所要求的对象,并且务实地说,这很可能就是您所需要的。不过,我会让该Show方法返回显式的Boolean,因为它是隐式使用的。

另一方面,如果您正在追求解耦和可测试性,那么从视图中提取模型只是第一步:然后您需要将演示者与工作表解耦,并且可能引入一些ISettingsAdapter将其抽象出来的接口,这样如果/当配置需要转到数据库或某些 .config 文件时,您的演示者代码不需要以任何方式更改...但这需要设计接口而无需考虑任何特定的具体实现,即无论数据是在工作表、某个平面文件还是某个数据库表中,都无需更改即可工作。

MVP 需要范式转变:MVP 不再是过程式编程,而是 OOP。OOP 是否对您的需求来说太过分了,取决于您愿意忍受多少耦合,以及面对未来的变化,这种耦合使您的代码变得多么脆弱。通常,抽象就足够了:使用命名范围而不是硬编码范围地址是提高抽象级别的一种方法;将工作表隐藏在由工作表代理类实现的适配器接口后面(无论您做什么,永远不要让工作表模块实现接口:它崩溃)是另一个 - 取决于您的“过度杀伤”阈值在哪里,但如果您确实实现了完全解耦并编写单元测试,没有人会责怪您做得太过分:您只是遵循每个程序员都努力追求的行业最佳实践,提高您的技能,并使以后更容易地使用该代码并在 . NET,无论是 VB 还是 C#。我怀疑有人会认为成熟的 MVP 在 .NET/WinForms 中是大材小用。