关于ms访问权限:Office类模块(对象)工厂的VBA

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中使用多态的能力,因此抽象接口类可以有多种不同的实现。
公开征求意见。开始:

  • 创建一个名为IExampleClass的简单Interface类,并在其上设置以下成员:
  • 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
  • 创建一个实现类ExampleClass。请注意,这具有Create方法。这是您的工厂方法。还请注意Self getter,它允许Create方法使用一种真正简洁的语法:
  • 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方法。

  • 现在让我们创建另一个实现IExampleClass接口的类,将其称为BackwardsExampleClass:
  • 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").ToString

    and it will return the output"John Smith"

  • 下一步在立即窗格中键入:

    1
       Debug.print BackwardsExampleClass.Create("John","Smith").ToString

    and it will return the output"Smith, John"