我有两个需要相互交互的对象,一个称为Collateral
,另一个称为Model
。 Model
是一个抽象类,由Model_A
,Model_B
,Model_AB
实现。每个抵押对象都有一个models
集合作为其属性之一。为了初始化每个Model
,我将需要使用来自Collateral
的信息(还有另一个对象将其称为User_Input
),该信息会随Model
的实现而变化。
我的问题是有可能使用一个构造函数,该构造函数将知道正在创建该对象的对象(在这种情况下,Model
知道什么实例化它的Collateral
的构造函数)?
如果不是,我假设有人会建议我使用抽象工厂模式,如果是这样,它将是什么样子(恐怕在OOP方面我还是很环保)?
为了简单起见,假设以下内容:Collateral
具有属性A,B,C和Models_CollectionCollateral
为其创建的每个Run
调用过程Models
(在Models_Collection中具有)Model
有一个名为Run
的公共Sub,下面的所有类中都实现了该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
型号_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
最佳答案
首先,让我们回答您的问题。如何动态创建均实现相同接口的不同类的实例?如前所述,VBA没有任何构造函数,所以您是对的。这里需要工厂模式。
我倾向于在接口类中定义一个公共枚举,以跟踪已实现的类。每当您实现一个新代码时,都需要将其添加到枚举和Factory中。我喜欢这样,需要更多的维护,但是如果没有适当的思考,我们对此无能为力。
因此,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
请注意,如示例中那样,最好使用枚举而不是字符串,这样可以在编译时检查错误而不是运行时。 (这消除了拼写错误的可能性。)
如果是我实施此操作,则将创建一个实际的单独类
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
类仅调用工厂并将其提供给工厂。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
现在,我将先发制人地回答您的下一个问题,因为我觉得您已经快要提问了。
我怎样才能准确知道我拥有哪种类型的模型?
好吧,为此您在this code review Q & A中有一些详细介绍的选项。这取决于您的用例,但是在这里。
TypeName(arg)
-返回对象的字符串名称。例如: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 ...