我有一个相对复杂的Access 2007用VBA编写的应用程序(4个枚举,7个模块,38个类模块,86个表单,以及大量的表和查询)。我发现使用对象工厂设计是有益的,但到目前为止,我无法找到一种干净的方法来实现这种类型的功能,而无需在VB或C#中轻松实现的标准抽象/继承。
有没有人有过在VBA中实施工厂设计的经验,甚至可能吗? ......或者是否有一个巧妙的“技巧”可以帮助我获得相同的总体目标?
我在工厂设计方面的经验仅限于C#,我从来没有在VB中完成它,所以也许VBA中有些东西是我所缺少的。
示例
我将收到具体日期。根据该日期,我需要计算2到5个其他日期之间的任何地方。计算这些日期的规则根据输入日期的“类型”而变化。
所以如果我的日期是07/15/2009,这是一个类型1的日期,它会返回
07/15/2010 for date 1,07 / 15/2011 for date 2,07 / 15/2012 for date 3,06 / 10/2012 for date 4 and 07/10/2012 for date 5
如果我把相同的日期,但把它作为日期类型2,我会得到 null表示日期1,null表示日期2,null表示日期3,06 / 10/2011(日期4)和07/10/2011(日期5)
所以对于每组规则,最少3个可能最多6个(现在这可以随时扩展)我将基本上输入一个开始日期...规则...并返回一个包含所有日期属性的对象。
我希望这有点帮助。
答案 0 :(得分:5)
我可能错过了问题的重点,但为什么不在标准模块中使用“工厂”方法/“构造函数”:
'default constructor
Public Function MyClassFactory() As MyClass
Set MyClassFactory = New MyClass
End Function
或者,如果您需要带有参数的“构造函数”:
'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
Etc等。
如果您始终使用此方法创建MyObject实例,则此“Factory Pattern”将替换构造函数。
您可以修改此代码以仅创建单例等。有时,VBA的缺点(例如,具有全局范围的标准模块)可以变成有用的东西。
要打电话给你,你就是这样做:
Dim Thing As MyClass
Set Thing = MyClassFactory(Param1, Param2)
对于这种事情,你非常接近建造者......或工厂......
我一定错过了什么。我对Factory模式的理解可能过于简单,但是你可能不希望在VBA中过于复杂。如果您发现需要,可能存在设计问题。
答案 1 :(得分:1)
这是一种在VBA中实现工厂模式的方法,该工具模式在Rubberduck网站https://rubberduckvba.wordpress.com/2016/07/05/oop-vba-pt-2-factories-and-cheap-hotels/上有很好的描述。 这是我试图解释它。我知道可能有一种更简洁的方法来做到这一点,但我试图证明两件事:使用工厂模式和依赖注入来构造对象而不必新建它们;以及在VBA中使用多态的能力,因此抽象接口类可以有多种不同的实现。 公开反馈。这是:
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
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
请注意,在此类中,Interface中每个成员的实现都有一个私有签名,因此使用此ExampleClass的代码只能从IExampleClass接口(抽象)对象访问ToString方法。
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设置为单例的技巧。 现在......您需要从项目中删除ExampleClass和BackwardsExampleClass,将其导出到文件夹,在文本编辑器中打开每个.cls文件,将Predeclared属性设置为“True”,保存每个.cls文件,然后重新导入将两个类文件放入您的项目中。这样做是为这两个实现IExampleClass接口的“Factory”类创建一个默认实例。
现在输入直接窗格:
Debug.print ExampleClass.Create("John","Smith").ToString
它将返回输出“John Smith”
下一步输入即时窗格:
Debug.print BackwardsExampleClass.Create("John","Smith").ToString
它将返回输出“Smith,John”