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.
中是矫枉过正的。
我一直在阅读 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.
中是矫枉过正的。