VBA для Office Class Module (Object) Фабрика - PullRequest
1 голос
/ 27 января 2011

У меня есть довольно сложное приложение для Access 2007, написанное на VBA (4 перечисления, 7 модулей, 38 модулей классов, 86 форм и множество таблиц и запросов). Я обнаружил ситуацию, когда было бы полезно использовать конструкцию «Фабрика объектов», но до сих пор я не могу найти простой способ реализации этого типа функций без стандартного абстрагирования / наследования, которое легко реализовать в VB или C #.

Кто-нибудь имел опыт внедрения заводского дизайна в VBA, и возможно ли это вообще? ... Или есть хитрый "трюк", который может помочь мне достичь той же цели?

Мой опыт работы на заводском дизайне ограничен C #, и я никогда не делал этого в VB, поэтому, возможно, в VBA есть что-то общее с VB, что мне не хватает.

Пример

Я буду получать конкретную дату. на основе этой даты мне нужно будет вычислить где-нибудь между 2 и 5 другими датами. правила расчета этих дат изменяются в зависимости от «типа» вводимой даты.

Так что, если у меня будет дата 15.07.2009, и это будет дата типа 1, она вернет

07/15/2010 для даты 1, 15.07.2011 для даты 2, 15 июля 2012 года для даты 3, 06/10/2012 для даты 4 и 07/10/2012 для даты 5

если бы я поставил ту же дату, но ввел ее как тип даты 2, я бы получил ноль для даты 1, ноль для даты 2, ноль для даты 3, 06/10/2011 для даты 4 и 07/10/2011 для даты 5

так что для каждого набора правил будет как минимум 3 возможных максимума из 6 (сейчас это всегда может быть расширено в любое время). Я в основном буду вводить начальную дату ... правило ... и возвращать объект, который будет содержать все свойства даты.

Надеюсь, это немного поможет.

Ответы [ 2 ]

5 голосов
/ 28 января 2011

Я, вероятно, пропустил суть вопроса, но почему бы не иметь "фабричный" метод / "конструктор" в стандартном модуле:

'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

и т. Д. И т. Д.

Если вы ВСЕГДА создаете экземпляры MyObject, используя это, этот «шаблон фабрики» заменяет конструктор.

Вы можете изменить этот код так, чтобы он создавал только синглтоны и т. Д. Иногда недостатки VBA (например, стандартные модули, имеющие глобальную область действия) можно превратить в нечто полезное.

Чтобы позвонить, просто сделайте:

Dim Thing As MyClass
Set Thing = MyClassFactory(Param1, Param2)

С такими вещами вы довольно близки к тому, чтобы иметь конструктор ... или фабрику ...

Я должен что-то упустить. Мое понимание шаблона «Фабрика», вероятно, слишком упрощено, но тогда вы, вероятно, не хотите становиться слишком сложным в VBA. Если вам это нужно, вероятно, существует проблема дизайна.

1 голос
/ 20 февраля 2017

Вот способ реализации Factory Pattern в VBA, который очень хорошо описан на веб-сайте Rubberduck https://rubberduckvba.wordpress.com/2016/07/05/oop-vba-pt-2-factories-and-cheap-hotels/. Вот моя попытка объяснить это.Я знаю, что, возможно, есть более краткий способ сделать это, но я пытаюсь продемонстрировать две вещи: использование фабричного шаблона и внедрение зависимостей для создания объектов без необходимости их нового создания;и возможность использовать полиморфизм в VBA, так что может быть несколько различных реализаций абстрактного класса интерфейса.Открыта для обратной связи.Вот так:

  1. Создайте простой интерфейсный класс с именем IExampleClass и установите для него следующие члены:
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.Это ваш фабричный метод.Также обратите внимание на собственный метод получения, который позволяет методу Create использовать действительно аккуратный синтаксис:
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, может получить доступ только к методу ToString из объекта интерфейса IExampleClass (abstract).

Теперь давайте создадим другой класс, который реализует интерфейс IExampleClass, назвав его BackwardsExampleClass:
   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 Class работать, чтобы вам не нужно было использовать новое ключевое слово для использования фабрики, и поэтому вы можете использовать Dependency Injection.Это трюк, который позволяет вам установить Factory как Singleton.Теперь ... вам нужно удалить ExampleClass и BackwardsExampleClass из вашего проекта, экспортировать его в папку, открыть каждый файл .cls в текстовом редакторе, установить для Predeclared Attribute значение «True», сохранить каждый файл .cls и повторно импортировать.оба файла классов в ваш проект.Это создает экземпляр по умолчанию обоих этих классов «Фабрика», которые реализуют интерфейс IExampleClass.

Теперь введите в ближайшей панели:

   Debug.print ExampleClass.Create("John","Smith").ToString

и он вернет вывод «Джон Смит»

Далее Введите в ближайшей панели:

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

и он будетвернуть вывод "Смит, Джон"

...