VBA for Office Class Module (Object) Factory
我有一个用VBA编写的Access 2007相对复杂的应用程序(4个枚举,7个模块,38个类模块,86个表单以及大量的表和查询)。我发现使用Object Factory设计将是有益的,但是到目前为止,如果没有在VB或C#中容易完成的标准抽象/继承,我无法找到一种干净的方法来实现这种类型的功能。
有没有人有在VBA中实施工厂设计的经验,甚至有可能吗? ...还是有一个整洁的"技巧"可以帮助我达到相同的总体目标?
我在工厂设计方面的经验仅限于C#,而我从来没有在VB中做到这一点,所以也许VBA中有些我缺少的VB通用的东西。
例
我将收到一个特定的日期。基于该日期,我将需要计算2至5个其他日期之间的任何时间。计算这些日期的规则会根据输入的日期"类型"而变化。
因此,如果我的日期为07/15/2009,并且这是1类日期,它将返回
日期1的07/15/2010日期2的07/15/2011日期3的07/15/2012,日期4的06/10/2012和日期5的07/10/2012
如果我输入相同的日期但将其输入为日期类型2,我会得到
日期1的null,日期2的null,日期3的null,日期4的06/10/2011和日期5的07/10/2011
因此,对于每组规则,至少有3个可能的最大值(最多6个)(目前,它随时可以扩展),我基本上是在输入开始日期...规则...并返回一个将包含所有日期属性。
我希望能有所帮助。
我可能已经错过了问题的要点,但是为什么在标准模块中没有"工厂"方法/"构造函数":
1 2 3 4 | 'default constructor Public Function MyClassFactory() As MyClass Set MyClassFactory = New MyClass End Function |
或者,如果您需要带有参数的"构造函数":
1 2 3 4 5 6 7 8 9 | 'Constructor with parameters Public Function MyClassFactory(Param1 As ParamObject1, Param2 As ParamObject2) As MyClass Dim MyThing As MyClass Set MyThing = New MyClass 'MyObjectInitializer is a Sub that does what a constructor should do MyThing.MyObjectInitializer Param1, Param2 Set MyClassFactory = MyThing End Function |
等等
如果始终使用此方法创建MyObject实例,则此"工厂模式"将替换构造函数。
您可以修改此代码以仅创建单例,等等。有时,VBA的缺点(例如,具有全局范围的标准模块)可以变成有用的东西。
要调用它,只需执行以下操作:
1 2 | Dim Thing As MyClass Set Thing = MyClassFactory(Param1, Param2) |
有了这种东西,您几乎可以拥有一个构造函数或工厂。
我肯定错过了什么。我对Factory模式的理解可能太简单了,但是您可能不想在VBA中变得太复杂。如果发现需要,则可能存在设计问题。
这是在VBA中实现工厂模式的一种方法,Rubberduck网站https://rubberduckvba.wordpress.com/2016/07/05/oop-vba-pt-2-factories-and-cheap-酒店/。
这是我尝试解释的方法。我知道可能有一种更简洁的方法来执行此操作,但是我试图演示两件事:使用工厂模式和依赖项注入来构造对象而不必重新创建它们;以及在VBA中使用多态的能力,因此抽象接口类可以有多种不同的实现。
公开征求意见。开始:
1
2
3
4
5
6
7
8
9
10 Option Explicit
Public Property Get Firstname() As String
End Property
Public Property Get Lastname() As String
End Property
Public Function ToString() As String
End Function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 Option Explicit
Private Type TExample
Firstname As String
Lastname As String
End Type
Private this As TExample
Implements IExampleClass
Public Property Get Firstname() As String
FirstName = this.Firstname
End Property
Public Property Let Firstname(Value As String)
this.Firstname = Value
End Property
Public Property Get Lastname() As String
Lastname = this.Lastname
End Property
Public Property Let Lastname(Value As String)
this.Lastname = Value
End Property
Public Property Get Self() As IExampleClass
Set Self = Me
End Property
Public Function Create(ByVal First As String, ByVal Last As String)
With New ExampleClass
this.Firstname = First
this.Lastname = Last
Set Create = Self
End With
End Function
Private Property Get IExampleClass_Firstname() As String
IExampleClass_Firstname = this.Firstname
End Property
Private Property Get IExampleClass_Lastname() As String
IExampleClass_Lastname = this.Lastname
End Property
Private Function IExampleClass_ToString() As String
IExampleClass_ToString = this.Firstname &"" & this.Lastname
End Function
请注意,在该类中,接口中每个成员的实现是如何具有私有签名的,因此,使用此ExampleClass的代码只能从IExampleClass接口(抽象)对象访问ToString方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 Option Explicit
Private Type TExample
Firstname As String
Lastname As String
End Type
Private this As TExample
Implements IExampleClass
Public Property Get Firstname() As String
Firstname = this.Firstname
End Property
Public Property Let Firstname(Value As String)
this.Firstname = Value
End Property
Public Property Get Lastname() As String
Lastname = this.Lastname
End Property
Public Property Let Lastname(Value As String)
this.Lastname = Value
End Property
Public Property Get Self() As IExampleClass
Set Self = Me
End Property
Public Function Create(ByVal First As String, ByVal Last As String)
With New ExampleClass
this.Firstname = First
this.Lastname = Last
Set Create = Self
End With
End Function
Private Property Get IBackwardsExampleClass_Firstname() As String
IExampleClass_Firstname = this.Firstname
End Property
Private Property Get IBackwardsExampleClass_Lastname() As String
IExampleClass_Lastname = this.Lastname
End Property
Private Function IBackwardsExampleClass_ToString() As String
IExampleClass_ToString = this.Lastname &"," & this.Firstname
End Function
这是使此Factory类工作的技巧,因此您无需使用New关键字即可使用Factory,因此您可以使用Dependency Injection。这是使您可以将Factory设置为Singleton的技巧。
现在...您需要从项目中删除ExampleClass和BackwardsExampleClass,将其导出到文件夹中,在文本编辑器中打开每个.cls文件,将Predeclared Attribute设置为" True",保存每个.cls文件,然后重新导入将两个类文件都放入您的项目中。这是为这两个实现IExampleClass接口的" Factory"类创建一个默认实例。
现在,在立即窗格中键入:
1 Debug.print ExampleClass.Create("John","Smith").ToStringand it will return the output"John Smith"
下一步在立即窗格中键入:
1 Debug.print BackwardsExampleClass.Create("John","Smith").ToStringand it will return the output"Smith, John"