vba - 如何借助 VBA 中初始化对象的属性来初始化对象

标签 vba oop excel factory factory-pattern

我有两个对象需要相互交互,一个叫做Collat​​eral,另一个叫做ModelModel是一个抽象类,由Model_AModel_BModel_AB实现。每个 Collat​​eral 对象都有一个 models 集合作为其属性之一。为了初始化每个 Model,我需要使用来自 Collat​​eral 的信息(还有另一个对象我们称之为 User_Input),这些信息会有所不同实现模型

我的问题是,是否可以使用一个构造函数,它会知道是什么对象在创建它(在这种情况下,Model 构造函数知道 Collat​​eral 实例化了它)? 如果不是,我假设有人会建议我使用抽象工厂模式,如果是的话,它会是什么样子(恐怕我对 OOP 还是一知半解)?

为简单起见,假设如下:

  • Collat​​eral 具有属性 A、B、C 和 Models_Collection
  • Collat​​eral 为它创建的每个 Model 调用过程 Run(在 Models_Collection 中)
  • Model 有一个名为 Run 的公共(public) Sub,它在下面的所有类中实现
  • 过程运行 操纵抵押品
  • Model_A 需要属性 A 来初始化
  • Model_B 需要属性 B 来初始化
  • Model_AB 需要属性 A、B 来初始化

这是我假设的简化代码:

抵押品

Dim A, B, C as Variant
Dim Model_Collection as Collection
Sub New_Model( Model_Type as String)
    Model_Collection.Add(Model_Implementation)
End Sub
Sub Execute_Models()
    For Each Model in Model_Collection
        Model.Run(Me)
    Next Model
End Sub

模型

    Sub Run()
    End

模型_A

Implements Model
Sub Class_Initialize()
    'Some code that takes property A from Collateral that Created this object
Sub Run(Collateral as Collateral)
    'Some Code
End Sub

模型_B

Implements Model
Sub Class_Initialize()
    'Some code that takes property B from Collateral that Created this object
Sub Run(Collateral as Collateral)
    'Some Code
End Sub

模型_AB

Implements Model
Sub Class_Initialize()
    'Some code that takes property A, and B from Collateral that Created this object
Sub Run(Collateral as Collateral)
    'Some Code
End Sub

最佳答案

首先,让我们回答您的问题。您如何动态创建都实现相同接口(interface)的不同类的实例?正如所指出的,VBA 没有任何构造函数,所以你是对的。这里需要工厂模式。

我倾向于在 Interface 类中定义一个公共(public)枚举来跟踪已实现的类。任何时候你实现一个新的,你都需要将它添加到你的枚举和工厂。这比我喜欢的要多一些维护,但如果没有适当的反射(reflection),我们对此无能为力。

因此,IModel 接口(interface):

Public Enum EModel
    ModelA
    ModelB
    ModelC
End Enum

Public Sub Run
End Sub

您的模型本身保持不变。然后回到您的 Collat​​eral 中,像这样实现您的 New_Model

private models as Collection

Public Sub New_Model(ByVal type As EModel) As IModel
    dim model As IModel
    Select Case type
        Case EModel.ModelA: Set model = New ModelA
        Case EModel.ModelB: Set model = New ModelB
        Case EModel.ModelC: Set model = New ModelC
    End Select

    models.Add model
End Sub

请注意,在您的示例中使用枚举比使用字符串更好,这样它会在编译时而不是运行时检查错误。 (这消除了拼写错误的可能性。)


如果由我来实现,我会创建一个实际的独立类 ModelFactory。然后 Collat​​eral 会调用模型工厂来获取它需要的东西。我认为它很好地分离了关注点。

根据您的要求,实现看起来像这样。

 Public Function CreateModel(Optional A As Variant, Optional B As Variant, Optional C As Variant)
     If Not A Is Nothing Then
         If B Is Nothing Then
             Set CreateModel = New ModelA
             Exit Function
         Else
             Set CreateModel = New ModelC
             Exit Function
         End If
     End If

     If Not B Is Nothing Then
         Set CreateModel = New ModelB
         Exit Function
     End If
 End Function

请注意,这完全消除了枚举和指定类型的需要。工厂根据可用的参数知道要创建什么。

然后你的 Collat​​eral 类简​​单地调用工厂并提供它所有的东西。

Private A,B,C
Private models As Collection
Private factory As ModelFactory

Private Sub Class_Initialize()
    Set factory = New ModelFactory
End Sub

Public Sub New_Model()
    models.Add factory.CreateModel(A,B,C)
End Sub

现在,我要先发制人地回答你的下一个问题,因为我觉得你已经快要问了。

How can I tell exactly what type of model I have?

好吧,为此您有一些选项,在 this code review Q & A 中有详细说明。 .这取决于您的用例,但它们就在这里。

  • TypeName(arg) - 返回对象的字符串名称。例如:

    Dim model As IModel
    Set model = New ModelA
    
    Debug.Print TypeName(model) '=> "ModelA"
    
  • TypeOfIs - 更严格地检查变量的类型。详细信息在我链接到的问题中,但这是一个示例。

    Dim model as IModel
    Set model = SomeFunctionThatReturnsAnIModel()
    
    If TypeOf model Is ModelA Then
        ' take some specific action for ModelA types
    Else If TypeOf model Is ModelB Then
        ' ModelB type specific action
    Else If ...
    

关于vba - 如何借助 VBA 中初始化对象的属性来初始化对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29287282/

相关文章:

vba - 更改列中数值的符号

excel - 如何使用 OpenPyXl 清除 Excel 工作簿中的一系列值

excel - VBA 将公式转换为注释

excel - 使用 VBA 复制多个范围

oop - 动画与MVC原理

matlab - Matlab OOP 中构造调用的顺序是什么?

vba - 在一个工作表中查找一个值,对其进行计数并将结果粘贴到另一个工作表中

excel - MS Access 2003 - Access 表单上嵌入的 Excel 电子表格

vba - 当存储在集合中时,如何更改类属性的值

javascript - 带有原型(prototype)与闭包的面向对象的 javascript