How to implement Factory default design in VBA?

1

I would like some methodology or example to try to simulate the application of the Factory project pattern in VBA.

    
asked by anonymous 20.06.2018 / 17:49

1 answer

2

I'm using the example from the book "Use the Head - Design Patterns", that of a pizzeria.

I have used two approaches to having Fachory Method in VBA:

1) Using a collection to avoid using many nested IF's    but for this all the authoring interfaces I use need to have the same signature.

2) I create an interface that selects my creative interfaces, so I can have the factory method whose objects can have creation methods with different signatures, and avoid using many nested IF's.

First approach:

HereIcreatetheIPizzainterface,whereallthepizzasshouldimplementit.

'todasaspizzasimplementamIPizzaPropertyGetgetNome()AsString:EndPropertyPropertyGetgetIngredientes()AsString:EndPropertyPropertyGetgetPreco()AsDouble:EndProperty

ThenIisolatethemethodtocreateapizzainanotherinterface.Inthisapproach,eachPizzaclassshouldimplementitsownpizza-makinginterface.IntheexamplewehaveclsPizzaCalabresaandclsPizzaQueijo,whichrespectivelyimplementICriarPizzaCalabresaandICriarPizzaQueijo.

class:ICriarPizzaCalabresa

'aclasseclsPizzaCalabresadeveimplementarICriarPizzaCalabresaFunctioncriar(ByValnomeDaPizzaAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizza:EndFunction

class:ICriarPizzaQueijo

'aclasseclsPizzaQueijodeveimplementarICriarPizzaQueijoFunctioncriar(ByValnomeDaPizzaAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizza:EndFunction

NotethattheyhavethesamesignatureandreturnthesameIPizzainterface.

Thedefaultmodule,typeEnum,wasmissing.

ThedefaultmoduleoftypeEnum,modEnumPizzalookslikethis:

PublicEnumenumTypePizzaCALABRESAQUEIJOEndEnum

TheclassclsPizzaCalabresalookslikethis:

ImplementsIPizzaImplementsICriarPizzaCalabresaPrivateTypeTTypenomeAsStringingredientesAsStringprecoAsDoubleEndTypePrivatethisAsTType'interfaceparaacriaçãodeumapizzadeCalabresaPrivateFunctionICriarPizzaCalabresa_criar(ByValnomeDaPizzaAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizzaWiththis.nome=nomeDaPizza.ingredientes=ingredientes.preco=precoEndWith'retornoareferênciadainterfaceIPizzadeumainstanciaclsPizzaCalabresaSetICriarPizzaCalabresa_criar=MeEndFunctionPrivatePropertyGetIPizza_getNome()AsStringIPizza_getNome=this.nomeEndPropertyPrivatePropertyGetIPizza_getIngredientes()AsStringIPizza_getIngredientes=this.ingredientesEndPropertyPrivatePropertyGetIPizza_getPreco()AsDoubleIPizza_getPreco=this.precoEndProperty

Andfinally,theclassclsPizzaQueijo:

ImplementsIPizzaImplementsICriarPizzaQueijoPrivateTypeTTypenomeAsStringingredientesAsStringprecoAsDoubleEndTypePrivatethisAsTType'interfaceparaacriaçãodeumapizzadeQueijoPrivateFunctionICriarPizzaQueijo_criar(ByValnomeDaPizzaAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizzaWiththis.nome=nomeDaPizza.ingredientes=ingredientes.preco=precoEndWith'retornoareferênciadainterfaceIPizzadeumainstanciaclsPizzaQueijoSetICriarPizzaQueijo_criar=MeEndFunctionPrivatePropertyGetIPizza_getNome()AsStringIPizza_getNome=this.nomeEndPropertyPrivatePropertyGetIPizza_getIngredientes()AsStringIPizza_getIngredientes=this.ingredientesEndPropertyPrivatePropertyGetIPizza_getPreco()AsDoubleIPizza_getPreco=this.precoEndProperty

NowwewillseehowtheFactoryclassofthisfirstapproachis:

ImplementsICriarPizzaCalabresaImplementsICriarPizzaQueijoPrivateTypeTType'Maspoderiaserumdicionário,Referencias=>MicrosoftScriptingRuntimeobjCollectionAsCollectionEndTypePrivatethisAsTTypePrivateSubClass_Initialize()DimobjInterfacePizzaQueijoAsICriarPizzaQueijoDimobjInterfacePizzaCalabresaAsICriarPizzaCalabresa'estouobtendoarefenciadainterfaceICriarPizzaQueijoeICriarPizzaQueijo'eguardandoemvariaveisSetobjInterfacePizzaQueijo=MeSetobjInterfacePizzaCalabresa=Me'paraevitarousodeIF'saninhados,usoumacolecao.'MaspoderiaserumdicionarioSetthis.objCollection=NewCollectionWiththis.objCollection'guardoasrefenciasnestacolecao,ondeachaveehdotipoEnum,'nestecasooenumQUEIJOeCALABRESA,domodulo'modEnumPizza'.AddobjInterfacePizzaQueijo,CStr(enumTypePizza.QUEIJO).AddobjInterfacePizzaCalabresa,CStr(enumTypePizza.CALABRESA)EndWith'asvariaveiscomasrefenciasasinterfacesestaoguardadasnacolecao'eporissonaoprecisamosmaisdelasSetobjInterfacePizzaQueijo=NothingSetobjInterfacePizzaCalabresa=NothingEndSubFunctionCriarPizza(ByValenumPizzaAsenumTypePizza,ByValnomeAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizzaDimobjInterfaceAsObjectSetobjInterface=this.objCollection(CStr(enumPizza))'Estamoschamandoometodoporligacaotardia('latebinding')'masnotequeparaissotodososmetodosdasinterfacesimplementadas'precisamteramesmaassinaturaSetCriarPizza=objInterface.criar(nome,ingredientes,preco)EndFunctionPrivateFunctionICriarPizzaCalabresa_criar(ByValnomeDaPizzaAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizzaDimobjPizzaAsclsPizzaCalabresaDimobjInterfacePizzaAsICriarPizzaCalabresaSetobjPizza=NewclsPizzaCalabresaSetobjInterfacePizza=objPizzaSetICriarPizzaCalabresa_criar=objInterfacePizza.criar(nomeDaPizza,ingredientes,preco)SetobjPizza=NothingSetobjInterfacePizza=NothingEndFunctionPrivateFunctionICriarPizzaQueijo_criar(ByValnomeDaPizzaAsString,ByValingredientesAsString,ByValprecoAsDouble)AsIPizzaDimobjPizzaAsclsPizzaQueijoDimobjInterfacePizzaAsICriarPizzaQueijoSetobjPizza=NewclsPizzaQueijoSetobjInterfacePizza=objPizzaSetICriarPizzaQueijo_criar=objInterfacePizza.criar(nomeDaPizza,ingredientes,preco)SetobjPizza=NothingSetobjInterfacePizza=NothingEndFunction

Andtoseeallthiswork,wecreatedthedefaultmodulecalledmodMain,whichlookslikethis:

ModMainmodule:

SubMain()DimobjPizzaAsIPizzaDimobjFactoryAsFactorySetobjFactory=NewFactorySetobjPizza=objFactory.CriarPizza(QUEIJO,"Pizza de Queijo", "mussarela, oregano, oleo de oliva, molho simples", 25.99)

    Debug.Print "Nome: " & objPizza.getNome
    Debug.Print "Ingredientes: " & objPizza.getIngredientes
    Debug.Print "Preco: " & objPizza.getPreco

    Debug.Print

    Set objPizza = objFactory.CriarPizza(CALABRESA, "Pizza de Calabresa", "Calabresa, cebola, oleo de oliva, oregano", 30.99)

    Debug.Print "Nome: " & objPizza.getNome
    Debug.Print "Ingredientes: " & objPizza.getIngredientes
    Debug.Print "Preco: " & objPizza.getPreco


End Sub

And the output in the immediate window is:

Nome: Pizza de Queijo
Ingredientes: mussarela, oregano, oleo de oliva, molho simples
Preco: 25,99

Nome: Pizza de Calabresa
Ingredientes: Calabresa, cebola, oleo de oliva, oregano
Preco: 30,99

Follow the example download link: Factory Method - Stackoverflow - EN-BR.xlsm

End of part one

2) I create an interface that selects my authoring interfaces, so I can have the factory method whose objects can have creation methods with different signatures, as well as avoiding the use of many nested IF's.

I have refuted the previous example adding little complexity. The novelty is that now we have to inform the ingredients in class Factory, besides the price to be due to the size of the pizza, which is Enum type.

Thedefaultmodulesfollow.

module:modEnumTamanho

PublicEnumenumTypeTamanhoPEQUENAMEDIAGRANDEFAMILIAEndEnum

module:modMain

SubMain()DimobjPizzaAsIPizzaDimobjFactoryAsFactorySetobjFactory=NewFactoryDebug.Print'Anteseraassim:SetobjPizza=objFactory.CriarPizza(CALABRESA,"Pizza de Calabresa", "Calabresa, cebola, oleo de oliva, oregano", 30.99)
    Set objPizza = objFactory.Fabricar.Calabresa("Pizza de Calabresa")

    Debug.Print "Nome: " & objPizza.getNome
    Debug.Print "Ingredientes: " & objPizza.getDescricao
    Debug.Print "Preco: " & objPizza.getPreco(GRANDE)

    Debug.Print

    'Antes era assim: Set objPizza = objFactory.CriarPizza(QUEIJO, "Pizza de Queijo", "mussarela, oregano, oleo de oliva, molho simples", 25.99)
    Set objPizza = objFactory.Fabricar.Queijo("Pizza de Queijo")

    Debug.Print "Nome: " & objPizza.getNome
    Debug.Print "Ingredientes: " & objPizza.getDescricao
    Debug.Print "Preco: " & objPizza.getPreco(PEQUENA)

End Sub

Now follow the class modules.

interface: IPizza

'todas as pizzas implementam IPizza
Property Get getNome() As String: End Property
Property Get getDescricao() As String: End Property
Property Get getPreco(ByVal tamanho As enumTypeTamanho) As Double: End Property

interface: ICriarPizzaQueijo

Function Criar(ByVal nomeDaPizza As String, dictIngredientes As Scripting.Dictionary, dictTamanhoPreco As Scripting.Dictionary) As IPizza: End Function

interface: ICriarPizzaCalabresa

Function Criar(ByVal nomeDaPizza As String, dictIngredientes As Scripting.Dictionary, dictTamanhoPreco As Scripting.Dictionary) As IPizza: End Function

interface: ISelectInterface

Property Get Calabresa(ByVal nome As String) As IPizza: End Property
Property Get Queijo(ByVal nome As String) As IPizza: End Property

Now follow the classes of the Pizzas

class: clsPizzaCalabresa

'
'Adicione a referencia 'Microsoft Scripting Runtime' em 'Ferramentas' => 'Referencias...'
'

Implements IPizza
Implements ICriarPizzaCalabresa

Private Type TType
    nome As String
    dictIngredientes As Scripting.Dictionary
    dictTamanhoPreco As Scripting.Dictionary
End Type

Private this As TType


Private Function ICriarPizzaCalabresa_criar(ByVal nomeDaPizza As String, dictIngredientes As Scripting.Dictionary, _
                 dictTamanhoPreco As Scripting.Dictionary) As IPizza

    With this

        .nome = nomeDaPizza
        Set .dictIngredientes = dictIngredientes
        Set .dictTamanhoPreco = dictTamanhoPreco

    End With

    Set ICriarPizzaCalabresa_criar = Me

End Function


Private Property Get IPizza_getDescricao() As String

    Dim i As Long
    Dim descricao As String

    descricao = ""
    For i = 0 To this.dictIngredientes.Count - 1

        If i <> this.dictIngredientes.Count - 1 Then
            descricao = descricao & this.dictIngredientes(i) & ", "
        Else
            descricao = descricao & this.dictIngredientes(i)
        End If

    Next i

    IPizza_getDescricao = descricao

End Property

Private Property Get IPizza_getNome() As String
    IPizza_getNome = this.nome
End Property


Private Property Get IPizza_getPreco(ByVal tamanho As enumTypeTamanho) As Double
    IPizza_getPreco = this.dictTamanhoPreco(tamanho)
End Property

class: clsPizzaQueijo

'
'Adicione a referencia 'Microsoft Scripting Runtime' em 'Ferramentas' => 'Referencias...'
'

Implements IPizza
Implements ICriarPizzaQueijo

Private Type TType
    nome As String
    dictIngredientes As Scripting.Dictionary
    dictTamanhoPreco As Scripting.Dictionary
End Type

Private this As TType


Private Function ICriarPizzaQueijo_criar(ByVal nomeDaPizza As String, dictIngredientes As Scripting.Dictionary, _
                 dictTamanhoPreco As Scripting.Dictionary) As IPizza

    With this

        .nome = nomeDaPizza
        Set .dictIngredientes = dictIngredientes
        Set .dictTamanhoPreco = dictTamanhoPreco

    End With

    Set ICriarPizzaQueijo_criar = Me

End Function


Private Property Get IPizza_getDescricao() As String

    Dim i As Long
    Dim descricao As String

    descricao = ""
    For i = 0 To this.dictIngredientes.Count - 1

        If i <> this.dictIngredientes.Count - 1 Then
            descricao = descricao & this.dictIngredientes(i) & ", "
        Else
            descricao = descricao & this.dictIngredientes(i)
        End If

    Next i

    IPizza_getDescricao = descricao

End Property

Private Property Get IPizza_getNome() As String
    IPizza_getNome = this.nome
End Property


Private Property Get IPizza_getPreco(ByVal tamanho As enumTypeTamanho) As Double
    IPizza_getPreco = this.dictTamanhoPreco(tamanho)
End Property

And why the class responsible for making the Pizzas

class: Factory

Implements ISelecioneInterface


Function Fabricar() As ISelecioneInterface

    Set Fabricar = Me

End Function


Private Property Get ISelecioneInterface_Calabresa(ByVal nome As String) As IPizza

    Dim objPizza As clsPizzaCalabresa
    Dim objInterfacePizza As ICriarPizzaCalabresa

    Dim dictTamanhoPreco As Scripting.Dictionary
    Dim dictIngredientes As Scripting.Dictionary

    Set dictTamanhoPreco = New Scripting.Dictionary
    Set dictIngredientes = New Scripting.Dictionary

    With dictTamanhoPreco
        .Add enumTypeTamanho.PEQUENA, 20.99
        .Add enumTypeTamanho.MEDIA, 25.99
        .Add enumTypeTamanho.GRANDE, 35.99
        .Add enumTypeTamanho.FAMILIA, 45.99
    End With

    With dictIngredientes
        .Add .Count, "Calabresa"
        .Add .Count, "cebola"
        .Add .Count, "molho simples"
        .Add .Count, "mussarela"
        .Add .Count, "azeitona"
        .Add .Count, "orégano"
        .Add .Count, "pimenta calabresa"
    End With

    Set objPizza = New clsPizzaCalabresa

    Set objInterfacePizza = objPizza

    Set ISelecioneInterface_Calabresa = objInterfacePizza.Criar(nome, dictIngredientes, dictTamanhoPreco)

End Property

Private Property Get ISelecioneInterface_Queijo(ByVal nome As String) As IPizza

    Dim objPizza As clsPizzaQueijo
    Dim objInterfacePizza As ICriarPizzaQueijo

    Dim dictTamanhoPreco As Scripting.Dictionary
    Dim dictIngredientes As Scripting.Dictionary

    Set dictTamanhoPreco = New Scripting.Dictionary
    Set dictIngredientes = New Scripting.Dictionary

    With dictTamanhoPreco
        .Add enumTypeTamanho.PEQUENA, 20.99
        .Add enumTypeTamanho.MEDIA, 25.99
        .Add enumTypeTamanho.GRANDE, 35.99
        .Add enumTypeTamanho.FAMILIA, 45.99
    End With

    With dictIngredientes
        .Add .Count, "Mussarela"
        .Add .Count, "parmesão"
        .Add .Count, "gorgonzola"
        .Add .Count, "catupiry"
        .Add .Count, "molho simples"
        .Add .Count, "tomate"
        .Add .Count, "orégano"
    End With

    Set objPizza = New clsPizzaQueijo

    Set objInterfacePizza = objPizza

    Set ISelecioneInterface_Queijo = objInterfacePizza.Criar(nome, dictIngredientes, dictTamanhoPreco)

End Property

Now just run the modMain, 'method' Main and we will see in the immediate window:

Nome: Pizza de Calabresa
Ingredientes: Calabresa, cebola, molho simples, mussarela, azeitona, orégano, pimenta calabresa
Preco: 35,99

Nome: Pizza de Queijo
Ingredientes: Mussarela, parmesão, gorgonzola, catupiry, molho simples, tomate, orégano
Preco: 20,99

I recommend using this latter approach.

Follow the link in the example worksheet:

Factory Method 2 - Stackoverflow - PT-BR

    
26.06.2018 / 15:38