Introdução a Módulos de Classe no VBA

O VBA suporta o uso de classes através de componentes chamados módulos de classe. Classes são usadas para criar objetos.

Introdução

Uma analogia bastante utilizada é dizermos que se um bolo é um objeto, sua receita é uma classe. Seguindo o raciocínio, é possível fazer vários bolos a partir de uma receita, ou vários objetos a partir de uma classe. Uma classe não aloca memória em tempo de execução, e um objeto sim, já que a classe possui apenas a definição do objeto que cria.

Uma classe descreve as propriedades e métodos de um objeto. Propriedades podem ser entendidas como características de um objeto, e métodos, ações que o mesmo promove. Por exemplo, considere o objeto Carro. Entre suas propriedades, podemos citar cor, quilometragem, chassi, marca, modelo, etc. Os métodos poderiam ser ações como dar a partida, acionar o para-brisa, frear, buzinar. Se fizermos a analogia que uma propriedade é um adjetivo, certamente um método é um verbo.

Declarar, Instanciar e Destruir um Objeto a Partir de uma Classe

Os objetos possuem um ciclo de vida. Primeiro, devem ser declarados. Então, são criados (tecnicamente é melhor falar instanciados), depois são utilizados (ou consumidos) e, for fim, são destruídos.

No VBA, um objeto é instanciado no momento em que a palavra chave New é utilizada.

Sub CriarObjeto()
 
    'Declarar:
    Dim oCarro As clsCarro
    
    'Instanciar:
    Set oCarro = New clsCarro
    
    'Consumir:
    '...
    
    'Destruir:
    Set oCarro = Nothing
 
End Sub

oCarro é o objeto e clsCarro é a classe. Repare que quando trabalhamos com objetos, as atribuições devem ser feitas com o uso da palavra chave Set, ao contrário de tipos de dados simples como Long, Integer, Date, etc., em que o uso da igualdade dá valor à variável.

Para que o exemplo acima funcione, é necessário que criemos a classe clsCarro no nosso projeto VBA:

Embora não seja obrigatório, é altamente recomendável destruir todos os objetos criados ao término da execução do seu programa. O gerenciamento de memória e coletor de lixo do VBE não são bons, e ao adotar essa prática você minimiza erros inesperados e até crashes no Excel.

Consumir Objetos

O exemplo a seguir mostra como acessar membros de um objeto de uma classe chamada clsEmpregado. Pelo código, podemos ver que a classe define três propriedades: Nome, Endereço e Salário. Cole o num Módulo de Classe chamado clsEmpregado:

'Esta Classe define três propriedades: Nome, Endereço e Salário.
'Seus valores são armazenados, respectivamente,
'nas variáveis aNome, aEndereço e aSalário.
 
Private aNome As String
Private aEndereço As String
Private aSalário As Double
    
'Abaixo seguem as declarações de propriedade de como são lidas e gravadas.
'Propriedade Nome:
Property Get Nome() As String
    Nome = aNome
End Property
Property Let Nome(pNome As String)
    aNome = pNome
End Property
 
'Propriedade Endereço:
Property Get Endereço() As String
    Endereço = aEndereço
End Property
Property Let Endereço(pEndereço As String)
    aEndereço = pEndereço
End Property
 
'Propriedade Salário:
Property Get Salário() As Double
    Salário = aSalário
End Property
Property Let Salário(pSalário As Double)
    aSalário = pSalário
End Property	
 
'Propriedade somente para leitura SalárioAnual:
Property Get SalárioAnual() As Double
    SalárioAnual = Salário * 12
End Property
 
Public Sub MostrarFolhaDePagamento()
    Dim sMensagem As String
    
    sMensagem = sMensagem & "Nome: " & Nome & vbCrLf
    sMensagem = sMensagem & "Data atual: " & Date & vbCrLf
    sMensagem = sMensagem & vbNewLine
    sMensagem = sMensagem & "Salário Mensal: " & Salário & vbCrLf
    sMensagem = sMensagem & "Salário Anual: " & SalárioAnual & vbCrLf
    MsgBox sMensagem, vbInformation
End Sub

Para cada uma das propriedades, há um procedimento Get e outro Let. Get é chamado quando se deseja ler o valor de uma propriedade e Let é chamado quando se deseja atribuir um valor a uma propriedade.

Para vermos nosso programa em funcionamento, devemos criar num módulo (comum, e não de classe) o seguinte código:

Sub UsoBásicoDeClasses()
    Dim oEmpregado As clsEmpregado
    Set oEmpregado = New clsEmpregado
    
    oEmpregado.Nome = "Felipe"
    oEmpregado.Endereço = "Rua Jardim, 20/603"
    oEmpregado.Salário = 1000
    
    Debug.Print "Nome: " & oEmpregado.Nome
    Debug.Print "Endereço: " & oEmpregado.Endereço
    Debug.Print "Salário: " & oEmpregado.Salário
    
    Set oEmpregado = Nothing
End Sub

Observe que ao escrever oEmpregado aparece o intellisense com todas as propriedades do objeto:

A vantagem imediata em usar classes é ter uma visualização completa dos membros de um objeto, além do ganho obtido em tempo de desenvolvimento.

Ao executar essa rotina, teremos como resultado na janela de verificação imediata (Ctrl+G):

Nome: Felipe
Endereço: Rua A, 12/901
Salário: 1000

Uso do With

Ao trabalhar com suas classes personalizadas, você pode usar o bloco With com os objetos que você criar:

Sub UsoBásicoDeClassesComWith()
    Dim oEmpregado As clsEmpregado
    
    Set oEmpregado = New clsEmpregado
    With oEmpregado
        .Nome = "Felipe"
        .Endereço = "Rua Jardim, 20/603"
        .Salário = 1000
        
        Debug.Print "Nome: " & .Nome
        Debug.Print "Endereço: " & .Endereço
        Debug.Print "Salário: " & .Salário
    End With
    
    Set oEmpregado = Nothing
End Sub

Atributos vs Propriedades vs Parâmetros

Dentro da classe, podemos observar, por exemplo Endereço, aEndereço e pEndereço. O que está havendo? Para definir uma simples propriedade, utilizei três membros diferentes com nomes semelhantes. Eles são necessários. Vamos rever a definição de atribuição de propriedade Endereço:

Property Let Endereço(pEndereço As String)
    aEndereço = pEndereço
End Property

Endereço é o nome da propriedade do objeto. A declaração de uma propriedade se assemelha bastante com a declaração de um subprocedimento e, como sabemos, um procedimento por si só não conseguem armazenar um valor após o término de sua execução. É para isso que utilizamos uma variável para armazenar o valor da propriedade, que é representada aqui por aEndereço (A letra a representa atributo). Ela é uma variável de nível de módulo, e retém os valores de um objeto enquanto o objeto estiver alocado na memória. Então, a propriedade Endereço é uma espécie de canal de comunicação entre a variável interna aEndereço e o ambiente externo.

pEndereço (A letra p representa parâmetro) é nada mais que o parâmetro de entrada do procedimento objeto. Ele possui o valor externo que será processado pela procedimento e atribuído à variável aEndereço. Por fim:

Property Get Endereço() As String
    Endereço = aEndereço
End Property

Endereço, nesse contexto, funciona igual uma função, que retorna o valor do atributo aEndereço ao procedimento que chamou a propriedade Endereço.

Simplificando Declaração de uma Propriedade

Se você não precisar inserir código no procedimento Get e Let de uma variável, você pode declarar a variável como pública que o VBE irá considera-lo como uma variável. Em outras palavras, o bloco de código:

Private aNome As String
 
Property Get Nome() As String
    Nome = aNome
End Property
Property Let Nome(pNome As String)
    aNome = pNome
End Property

É equivalente a simplesmente:

Public Nome As String
Note que ao utilizar a palavra-chave Public numa variável que está dentro de um módulo de classe, ela não é pública para todo projeto, como ocorre em declarações em módulos regulares. Public em módulos de classe significa que a variável declarada pode ser acessada por procedimentos que não estejam dentro da classe.

Propriedades Somente Como Leitura

No exemplo anterior, todas as propriedades possuíam a declaração Let e Get.

É possível criar uma propriedade somente como leitura. Para tal, poderíamos definir, por exemplo, uma propriedade chamada SalárioAnual, que seria dada pelo produto do salário mensal e 12:

'Propriedade somente para leitura SalárioAnual:
Property Get SalárioAnual() As Double
    SalárioAnual = Salário * 12
End Property
Note que poderíamos ter utilizado a variável de módulo (que aqui tem a função de atributo) aSalário ao invés da propriedade Salário. No entanto, as boas práticas de programação dizem que quando estamos numa classe, devemos utilizar o valor retornado pela propriedade, e não a variável que armazena o valor da propriedade. Essa boa prática tem um custo que é tornar a depuração do código mais trabalhosa, uma vez que todo acesso à propriedade Salário desvia o código para seu procedimento respectivo. Por outro lado, ao usar o valor da propriedade, você terá garantido que o valor atribuído já foi processado e validado por sua classe.

O fato dessa propriedade não possuir a instrução Let é o que a caracteriza somente como leitura, tornando impossível fazer uma atribuição direta a ela.

Restringindo Valores de Entrada de uma Propriedade

Uma grande vantagem em usar classes é possibilidade de tratar os dados de entrada e saída da classe. Para o exemplo da classe clsEmpregado, vamos adicionar código para ser impossível atribuir um valor negativo à propriedade Salário. Poderíamos adaptar sua propriedade Let na forma mostrada abaixo:

Property Let Salário(d As Double)
    'Restringir valores de entrada para Salário:
    If pSalário > 0 Then
        aSalário = pSalário
    Else
        'O valor do salário deve ser maior que zero!
        aSalário = 1
    End If 
End Property

Criar Métodos na Classe

Até agora foi mostrado apenas como trabalhar com propriedades nas classes. Você pode definir métodos também. Acrescente o bloco de código abaixo na classe clsEmpregado:

Public Sub MostrarFolhaDePagamento()
    Dim sMensagem As String
    
    sMensagem = sMensagem & "Nome: " & Nome & vbCrLf
    sMensagem = sMensagem & "Data atual: " & Date & vbCrLf
    sMensagem = sMensagem & vbNewLine
    sMensagem = sMensagem & "Salário Mensal: " & Salário & vbCrLf
    sMensagem = sMensagem & "Salário Anual: " & SalárioAnual & vbCrLf
    MsgBox sMensagem, vbInformation 
End Sub

Agora, coloque o código abaixo num módulo comum e execute:

Sub ExemploMétodo()
    Dim oEmpregado As clsEmpregado
    
    Set oEmpregado = New clsEmpregado
    oEmpregado.Nome = "Felipe"
    oEmpregado.Endereço = "Rua Jardim, 20/603"
    oEmpregado.Salário = 1000
    oEmpregado.MostrarFolhaDePagamento
    
    Set oEmpregado = Nothing
End Sub

O resultado será:

Referenciando Propriedades e Métodos da Classe

Quando escrevemos código dentro de uma classe, ao invés de escrever Nome, Salário e SalárioAnual, podemos escrever Me.Nome, Me.Salário e Me.SalárioAnual. Em outras palavras, no contexto dentro de uma classe, Me se refere a ela mesma. Uma vantagem de se usar o Me é o fato de aparecer o intellisense com todos os membros (isto é, propriedades, métodos, constantes e enumerações) da classe:

Note que ícones de propriedades são diferentes de ícones de métodos.

Eventos Padrões de uma Classe

Toda classe no VBA possui dois eventos padrões, de nome fixo. Um chama-se Class_Initialize, e é executado quando um objeto é instanciado. O outro, Class_Terminate, é executado quando o objeto é destruído. Você não é obrigado a colocar código nesses dois eventos.

Para exemplificar, crie uma classe chamada clsCasa com o código abaixo:

Private aEndereço As String
Private aDólares As Double
 
'Eventos
Private Sub Class_Initialize()
    Me.Endereço = "Rua das Flores, 105"
End Sub
Private Sub Class_Terminate()
    MsgBox "Um objeto cuja propriedade Endereço é " & Me.Endereço & " foi destruído.", vbInformation
End Sub
 
'Propriedades
Property Get Endereço() As String
    Endereço = aEndereço
End Property
Property Let Endereço(pEndereço As String)
    aEndereço = pEndereço
End Property
 
Property Get Dólares() As Double
    Dólares = aDólares
End Property
Property Let Dólares(pDólares As Double)
    aDólares = pDólares
End Property

Num módulo regular, coloque o código abaixo:

Sub ExemploEventos()
    Const VALOR_DÓLAR_DO_DIA = 3.03
    
    Dim oCasa As clsCasa
    
    'O evento Class_Initialize é chamado quando se cria o objeto:
    Set oCasa = New clsCasa
    
    oCasa.Dólares = 150000 * VALOR_DÓLAR_DO_DIA
    
    'O evento Class_Terminate é chamado quando se destrói o objeto:
    Set oCasa = Nothing
End Sub
Se você retirar a instrução Set oCasa = Nothing do código acima verá que o ponto de execução desviará de End Sub para o procedimento destrutor do objeto (ou seja, foi destruído implicitamente). Pode-se argumentar então que destruir um objeto explicitamente é desnecessário. Volto a insistir que a melhor forma de destruir um objeto é explicitamente, e que em muitos casos você, como desenvolvedor, terá menos problemas em sistemas mais complexos e melhor gerenciamento de memória. A título de exemplo, existem alguns cenários de crashes no Excel em formulários quando os mesmos não são destruídos explicitamente. Infelizmente, pelo fato do problema ser também de design do VBE, não consigo descrever um passo a passo para reproduzir esse tipo de problema. Além disso, um bom programa é aquele que encerra quando a instrução End Sub do método pai é executada, sem disparar toneladas de coletores de lixo dos objetos pendurados na memória.

Normalmente uso o evento Class_Initialize para definir valores iniciais e padrões de um objeto. No exemplo acima, ao criar um objeto clsCasa, define-se automaticamente que a propriedade Endereço do mesmo é Rua das Flores, 105.

Nesse sentido, você pode usar esse evento para definir propriedades padrão ao criar um objeto. Suponha que você crie vários objetos de uma classe clsVeículo para usar num ambiente em que os veículos são, predominantemente, carros. Se existir uma propriedade chamada QuantidadeRodas, você poderia atribuir 4 à essa propriedade dentro do evento Class_Initialize, e atribuir explicitamente oVeículo.QuantidadeRodas = 2 fora da classe apenas nos casos de quando o veículo é uma moto.

O Class_Terminate é utilizado para colocar códigos de limpeza no ato da destruição de um objeto. No nosso exemplo, mostra-se apenas uma notificação de que o objeto foi destruído.

Os Problemas da Auto Instanciação

Alternativamente, você pode criar um objeto dessa forma:

Sub CriarObjetoFormaNãoRecomendada()
 
    'Declarar e instanciar:
    Dim oCarro As New clsCarro
    
    'Consumir
    '...
    
    'Destruir
    Set oCarro = Nothing
 
End Sub

Foi feita a declaração e criada uma instância do objeto numa única instrução. O nome dessa técnica é auto instanciação de variável. No VBA, não é recomendável utilizá-la por dois motivos:

  • Aumenta o overhead do código porque cada chamada a um objeto criado dessa classe irá disparar o evento de inicialização do mesmo. Ao criar um objeto dessa forma e fazer uma simples atribuição como, por exemplo, oCarro.Cor = "Verde", o evento Class_Initialize será disparado, e isso é altamente indesejável.
  • Não há como testar se uma variável criada desse tipo é Nothing porque a própria instrução de teste irá criar uma instância do objeto, retornando, então, sempre False para o teste. Nesse exemplo, o teste If oCarro Is Nothing Then... sempre irá passar.

Criar mais de um Objeto com uma Classe

No exemplo a seguir, foram criados três objetos do mesmo tipo, mas com propriedades diferentes:

Sub VáriosObjetos()
    Dim oEmp1 As clsEmpregado
    Dim oEmp2 As clsEmpregado
    Dim oEmp3 As clsEmpregado
 
    Set oEmp1 = New clsEmpregado
    Set oEmp2 = New clsEmpregado
    Set oEmp3 = New clsEmpregado
    
    oEmp1.Nome = "Felipe"
    oEmp1.Endereço = "Rua Jardim, 20/603"
    oEmp1.Salário = 1000
    '---
    oEmp2.Nome = "Renata"
    oEmp2.Endereço = "Praça das Flores, 305"
    oEmp2.Salário = 1500
    '---
    oEmp3.Nome = "Rodrigo"
    oEmp3.Endereço = "Av. Castro, 50/101"
    oEmp3.Salário = 2000
    
    oEmp1.MostrarFolhaDePagamento
    oEmp2.MostrarFolhaDePagamento
    oEmp3.MostrarFolhaDePagamento
    
    Set oEmp1 = Nothing
    Set oEmp2 = Nothing
    Set oEmp3 = Nothing
End Sub

O VBA não mistura os valores das propriedades (na verdade atributos) dos objetos criados. Cada objeto aloca espaço na memória para guardar os próprios valores de cada propriedade.

Criar uma Coleção de Objetos

Você pode adicionar objetos em coleções. Suponha que você tenha a tabela abaixo:

Use o código a seguir para criar um objeto por linha da tabela, povoar as propriedades da tabela de acordo as colunas respectivas e, em seguida, mostrar os dados dos objetos na janela de verificação imediata:

Sub ColeçãoDeObjetos()
    Dim tblEmpregados As ListObject
    Dim oEmpregado As clsEmpregado
    Dim cEmpregados As Collection
    Dim iListRow As ListRow
    Dim iItem As Long
 
    'Definir tabela de Empregados
    Set tblEmpregados = ThisWorkbook.Worksheets("Coleções").ListObjects("Empregados")
    
    'Inicializar Coleção?
    Set cEmpregados = New Collection
    
    'Criar e popular objetos
    For Each iListRow In tblEmpregados.ListRows
        Set oEmpregado = New clsEmpregado
        oEmpregado.Nome = iListRow.Range(1)
        oEmpregado.Endereço = iListRow.Range(2)
        oEmpregado.Salário = iListRow.Range(3)
        
        'Adiciona objeto à coleção:
        cEmpregados.Add oEmpregado
    Next iListRow
    
    'Mostrar resultados
    For Each oEmpregado In cEmpregados
        Debug.Print oEmpregado.Nome, oEmpregado.Endereço, oEmpregado.Salário
    Next oEmpregado
    
    'Ou, com laço do tipo For...Next
    For iItem = 1 To cEmpregados.Count
        Set oEmpregado = cEmpregados(iItem)
        Debug.Print oEmpregado.Nome, oEmpregado.Endereço, oEmpregado.Salário
    Next iItem
        
End Sub

Você pode remover um item da coleção se desejar. A instrução abaixo remove o terceiro item da coleção do nosso exemplo:

cEmpregados.Remove 3

Gerador de Propriedades

Usando um “código para gerar código”, você pode tornar menos moroso o processo de escrever declarações de propriedades:

Sub GerarPropriedade()
    Dim sAtributo As String
    Dim sInstrução As String
    Dim sParâmetro As String
    Dim sPropriedade As String
    Dim sSaída As String
    Dim sTipoDeDados As String
    Dim vInstruções() As String
    
    sInstrução = InputBox(Prompt:="Digite a linha de declaração do atributo:", _
                          Default:="Private aNome As String")
    If sInstrução = "" Then Exit Sub
    
    vInstruções = Split(sInstrução)
    sAtributo = vInstruções(1)
    sPropriedade = Mid(sAtributo, 2)
    sParâmetro = "p" & sPropriedade
    sTipoDeDados = vInstruções(3)
    
    sSaída = ""
    sSaída = sSaída & "Property Get " & sPropriedade & "() As " & sTipoDeDados & vbNewLine
    sSaída = sSaída & vbTab & sPropriedade & " = " & sAtributo & vbNewLine
    sSaída = sSaída & "End Property" & vbNewLine & vbNewLine
    sSaída = sSaída & "Property Let " & sPropriedade & "(" & sParâmetro & " As " & sTipoDeDados & ")" & vbNewLine
    sSaída = sSaída & vbTab & sAtributo & " = " & sParâmetro & vbNewLine
    sSaída = sSaída & "End Property" & vbNewLine
    Debug.Print sSaída
End Sub

Se você entrar Private aNome As String na janela, obterá as declarações Get e Let na janela de verificação imediata:

Property Get Nome() As String
    Nome = aNome
End Property
Property Let Nome(pNome As String)
    aNome = pNome
End Property

Você pode criar versões mais sofisticadas desse código, como por exemplo: obter o esquema de uma tabela de um banco de dados e gerar classes no VBE mapeando cada um dos campos a uma propriedade. Use a criatividade. Não deixe de verificar também o MZ Tools, que possui um ótimo assistente para criar propriedades em classes.

Referências

Chip Pearson

Download

Para fazer download do arquivo de exemplo deste artigo, clique aqui.

Sobre Felipe Gualberto

Microsoft Most Valuable Professional (MVP) de Excel.
Esta entrada foi publicada em Tutoriais e marcada com a tag , , , , , , , , , . Adicione o link permanente aos seus favoritos.
  • Henderson

    Po, vc escreve muito bem cara, parabéns.
    Me considero um usuário muito avançado no Excel e é difícil ver novidades por aí.
    Não uso Classes por achar chato demais. Tudo que se faz com classes se faz sem elas, mas elas facilitam a vida. São uma boa prática.
    Só que sempre tive muito preconceito com usar classe no VBA. Você me convenceu a usar, haha. Amanhã mesmo vou implementar em um projeto que estou desenvolvendo. Vou refazer 4 horas de trabalho que tive hoje para usar classes porque vai me facilitar a vida daqui pra frente.

  • Eduardo

    De modo geral o que executa mais rápido, uma macro comum ou modulo de classe ?

    mesmo com uma explicação tão detalhada ainda acho complicado o uso, e como o Henderson falou, é bem chato ,principalmente pq não uso o excel profissionalmente.

    mas se a execução for melhor acho que vale a pena perder um tempo para aprender e implementar as classes nos projetos.

    • Nunca fiz um teste de comparação de velocidade entre os dois. Acredito que o desempenho deve ser semelhante.
      No entanto, mesmo se usando módulos de classe for mais lento, não abriria mão do uso da técnica.

      • Eduardo

        Estava vendo o forum que vc indicou e realmente tem uma serie de vantagens.
        teria sido perfeito para minha planilha
        eu uso muito arrays e não uso range fixas e classes simplificaria muito minhas macros
        mas não sei se vale a pena refazer as dezenas de macros e ir aprendendo no percusso

  • Ari Maximiano

    eEmpregados.Nome …
    “objeto é obrigatório”
    Fiz o exemplo e tive essa de erro como retorno ao executar. Não entendi de onde veio esse “eEmpregados.Nome”
    cEmpregados é a coleção
    oEmpregados é o objeto gerado a partir da classe clsEmpregado
    e o eEmpregado?

    De toda forma muito útil seu post, obrigado!

    • Ari, falha minha.
      Baixe o arquivo no final do artigo e veja que eEmpregados.Nome tem o valor = 1 na definição da enumeração do início do módulo. Esqueci de colocar essa parte de código no artigo, vou corrigir.
      Basta você substituir os valores que aparecem por 1, 2 e 3, respectivamente que a macro irá funcionar da maneira esperada.

  • Ari Maximiano

    Prezado, abusar da sua atenção…
    depois que li seu post comecei fazer um monte de testes com módulos de classe tentando aprofundar um pouco. De ontem pra hoje estou tentando fazer uma coisa aqui que não estou conseguindo nem a pau! Veja bem: estou tentando fazer um exemplo bem prático de uma aplicação que registra os pedidos de uma mesa de bar, lanchonete ou restaurante, enfim, tanto faz. Criei uma classe simples “clsMesa” e nela somente 3 propriedades, como é apenas um exercício, porém dentre uma das propriedades da Mesa será a lista de produtos consumidos que estou entendendo que seria uma coleção de objetos de uma suposta classe “clsProdutos”. Consegui ser claro? Já tentei de tudo para ao criar um objeto da classe clsMesa eu consiga inserir outros objetos da classe clsProduto, mas nada dá certo. Em um módulo comum consegui fazer isso criando um tipo Mesa com um dos elementos chamando Lista do tipo Collection, mas utilizando um módulo de classe nada. Não sei se consegui ser claro com meu problema eu agradeceria muito se pudesse me dar alguma dica sobre isso. Muito obrigado!

  • Veja como eu eu modelaria seu problema:
    clsProduto
    clsMesa
    clsPedido

    Propriedades de clsPedido:
    aMesa As clsMesa
    aProdutos as Collection ‘Coleção de 0 ou mais clsProduto

    Propriedades de clsProduto:
    aDescrição as String
    aPreço as Single

    Propriedades de clsMesa
    aNúmero as Long

    Num procedimento em um módulo regular, você deve inicializar todos as mesas produtos disponíveis. Não é uma má ideia você ter uma coleção global Produtos e outra Mesas que tenham informações de todas as mesas.
    O procedimento regular deve ter também a coleção Pedidos. Daí, toda vez que você fizer um pedido novo, instancie um objeto da classe clsPedido e adicione na coleção Pedidos.

    Claro que seria necessário analisar com mais detalhes sua necessidade antes de chegar em um modelo definitivo.

  • Tiago Mantovani

    Mano parabens, artigo fantastico!!