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

VBA Settings Dialog using MVP - do I need a model?

我一直在阅读 MVP(模型-视图-演示者)及其变体(被动视图、监督视图)的许多示例,以尝试使我的解决方案在 VBA(在此实例中使用 Excel 作为主机)。我发现的问题是在 VBA 中找到好的、简单的例子,这些例子对于我需要的(希望)简单的例子来说并不是完全矫枉过正。

我正在尝试创建一个 "settings" 对话,将某些配置存储在工作表中(这是我的 "repository")。

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

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

这是我的“presenter”(这里我使用范围名称作为源和配置目标):

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

现在是“View”(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

在这一点上,我对在上面添加模型方面的可能方向感到困惑 - 问题是:这个简单的例子是否需要这个?

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

如果松散耦合的组件和单元测试table 逻辑不是必需的,那么成熟的 MVP 确实有点矫枉过正,并且将 "model" 作为 [= 上的属性公开46=] 绝对 足够好,因为它已经帮助您 "presenter" 无需关心表单控件。您正在将表单视为它乞求成为的对象,从实用的角度来说,这很可能就是您所需要的。不过,我会将 Show 方法 return 设为显式 Boolean,因为它是隐式使用的。

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

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

中是矫枉过正的。