如何借助 VBA 中初始化对象的属性来初始化对象
How Can I Initialize an object with help of properties of initializing object in VBA
我有两个对象需要相互交互,一个叫做 Collateral
,另一个叫做 Model
。 Model
是一个抽象Class是由Model_A
、Model_B
、Model_AB
实现的。每个 Collateral 对象都有一个 models
的集合作为其属性之一。为了初始化每个 Model
,我将需要使用来自 Collateral
的信息(还有另一个对象我们称之为 User_Input
),该信息将随着 Model
的实现而变化。
我的问题是,是否可以使用一个构造函数来了解创建它的对象(在本例中 Model
构造函数知道 Collateral
实例化了它)?
如果不是,我假设有人会建议我使用抽象工厂模式,如果是的话,它会是什么样子(恐怕我在 OOP 方面仍然是绿色的)?
为简单起见,假设如下:
Collateral
具有属性 A、B、C,Models_Collection
Collateral
为它创建的每个 Models
调用过程 Run
(在 Models_Collection 中)
Model
有一个名为 Run
的 public Sub,它在所有 类 波纹管 中实现
- 程序
Run
操纵Collateral
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
Model_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
Model_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
Model_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
首先,让我们回答你的问题。您如何动态创建实现相同接口的不同 class 的实例?正如所指出的,VBA 没有任何构造函数,所以你是对的。这里需要工厂模式。
我倾向于在接口 class 中定义一个 public 枚举来跟踪已实现的 classes。任何时候你实现一个新的,你都需要将它添加到你的枚举和工厂。这比我喜欢的要多一些维护,但如果没有适当的反思,我们对此无能为力。
因此,IModel
接口:
Public Enum EModel
ModelA
ModelB
ModelC
End Enum
Public Sub Run
End Sub
您的模型本身保持不变。然后回到你的 Collateral
像这样实现你的 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
请注意,在您的示例中使用枚举比使用字符串更好,这样它会在编译时而不是运行时检查错误。 (这消除了拼写错误的可能性。)
如果是我实现这个,我会创建一个实际的单独 class ModelFactory
。然后 Collateral
会调用模型工厂来获取它需要的东西。我认为它很好地分离了关注点。
根据您的要求,实现看起来像这样。
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
请注意,这完全消除了枚举和指定类型的需要。工厂知道根据可用的参数创建什么。
然后你的 Collateral
class 只需调用工厂并提供它所有的东西。
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)
- Returns 对象的字符串名称。例如:
Dim model As IModel
Set model = New ModelA
Debug.Print TypeName(model) '=> "ModelA"
TypeOf
和 Is
- 更严格地检查变量的类型。详细信息在我链接到的问题中,但这里有一个例子。
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 ...
我有两个对象需要相互交互,一个叫做 Collateral
,另一个叫做 Model
。 Model
是一个抽象Class是由Model_A
、Model_B
、Model_AB
实现的。每个 Collateral 对象都有一个 models
的集合作为其属性之一。为了初始化每个 Model
,我将需要使用来自 Collateral
的信息(还有另一个对象我们称之为 User_Input
),该信息将随着 Model
的实现而变化。
我的问题是,是否可以使用一个构造函数来了解创建它的对象(在本例中 Model
构造函数知道 Collateral
实例化了它)?
如果不是,我假设有人会建议我使用抽象工厂模式,如果是的话,它会是什么样子(恐怕我在 OOP 方面仍然是绿色的)?
为简单起见,假设如下:
Collateral
具有属性 A、B、C,Models_CollectionCollateral
为它创建的每个Models
调用过程Run
(在 Models_Collection 中)Model
有一个名为Run
的 public Sub,它在所有 类 波纹管 中实现
- 程序
Run
操纵Collateral
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
Model_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
Model_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
Model_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
首先,让我们回答你的问题。您如何动态创建实现相同接口的不同 class 的实例?正如所指出的,VBA 没有任何构造函数,所以你是对的。这里需要工厂模式。
我倾向于在接口 class 中定义一个 public 枚举来跟踪已实现的 classes。任何时候你实现一个新的,你都需要将它添加到你的枚举和工厂。这比我喜欢的要多一些维护,但如果没有适当的反思,我们对此无能为力。
因此,IModel
接口:
Public Enum EModel
ModelA
ModelB
ModelC
End Enum
Public Sub Run
End Sub
您的模型本身保持不变。然后回到你的 Collateral
像这样实现你的 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
请注意,在您的示例中使用枚举比使用字符串更好,这样它会在编译时而不是运行时检查错误。 (这消除了拼写错误的可能性。)
如果是我实现这个,我会创建一个实际的单独 class ModelFactory
。然后 Collateral
会调用模型工厂来获取它需要的东西。我认为它很好地分离了关注点。
根据您的要求,实现看起来像这样。
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
请注意,这完全消除了枚举和指定类型的需要。工厂知道根据可用的参数创建什么。
然后你的 Collateral
class 只需调用工厂并提供它所有的东西。
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)
- Returns 对象的字符串名称。例如:Dim model As IModel Set model = New ModelA Debug.Print TypeName(model) '=> "ModelA"
TypeOf
和Is
- 更严格地检查变量的类型。详细信息在我链接到的问题中,但这里有一个例子。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 ...