La ventaja de utilizar clases en lugar de simplemente subrutinas es que las clases crean un nivel de abstracción que le permite escribir código más limpio. Es cierto que si nunca antes has usado clases en VBA, hay una curva de aprendizaje, pero creo que definitivamente vale la pena el tiempo para resolverlo.
Una indicación clave que debe cambiar a las clases es si constantemente agrega parámetros a sus funciones y subrutinas. En este caso, casi siempre es mejor usar clases.
he copiado una explicación de las clases de one of my previous Stack Overflow answers:
Aquí hay un largo ejemplo de cómo el uso de una clase que podría ayudarle. Aunque este ejemplo es extenso, le mostrará cómo algunos principios de programación orientada a objetos realmente pueden ayudarlo a limpiar su código.
En el editor de VBA, vaya al Insert > Class Module
. En la ventana Propiedades (en la parte inferior izquierda de la pantalla de forma predeterminada), cambie el nombre del módulo a WorkLogItem
. Agregue el código siguiente a la clase:
Option Explicit
Private pTaskID As Long
Private pPersonName As String
Private pHoursWorked As Double
Public Property Get TaskID() As Long
TaskID = pTaskID
End Property
Public Property Let TaskID(lTaskID As Long)
pTaskID = lTaskID
End Property
Public Property Get PersonName() As String
PersonName = pPersonName
End Property
Public Property Let PersonName(lPersonName As String)
pPersonName = lPersonName
End Property
Public Property Get HoursWorked() As Double
HoursWorked = pHoursWorked
End Property
Public Property Let HoursWorked(lHoursWorked As Double)
pHoursWorked = lHoursWorked
End Property
El código anterior nos dará un objeto inflexible de tipos que es específico a los datos con los que estamos trabajando. Cuando se utiliza matrices multidimensionales para almacenar sus datos, el código se parece a esto: arr(1,1)
es el ID, arr(1,2)
es el PersonName y arr(1,3)
es la hoursWorked. Usando esa sintaxis, es difícil saber qué es qué. Supongamos que todavía cargas tus objetos en una matriz, pero en su lugar usa el WorkLogItem
que creamos anteriormente. Este nombre, usted podría hacer arr(1).PersonName
para obtener el nombre de la persona. Eso hace que tu código sea mucho más fácil de leer.
Sigamos con este ejemplo. En lugar de almacenar los objetos en el conjunto, intentaremos usar un collection
.
A continuación, agregue un nuevo módulo de clase y llámelo ProcessWorkLog
. Coloque el código siguiente en llegar:
Option Explicit
Private pWorkLogItems As Collection
Public Property Get WorkLogItems() As Collection
Set WorkLogItems = pWorkLogItems
End Property
Public Property Set WorkLogItems(lWorkLogItem As Collection)
Set pWorkLogItems = lWorkLogItem
End Property
Function GetHoursWorked(strPersonName As String) As Double
On Error GoTo Handle_Errors
Dim wli As WorkLogItem
Dim doubleTotal As Double
doubleTotal = 0
For Each wli In WorkLogItems
If strPersonName = wli.PersonName Then
doubleTotal = doubleTotal + wli.HoursWorked
End If
Next wli
Exit_Here:
GetHoursWorked = doubleTotal
Exit Function
Handle_Errors:
'You will probably want to catch the error that will '
'occur if WorkLogItems has not been set '
Resume Exit_Here
End Function
La clase anterior se va a utilizar para "hacer algo" con un colleciton de WorkLogItem
. Inicialmente, simplemente lo configuramos para contar la cantidad total de horas trabajadas. Probemos el código que escribimos.Cree un nuevo Módulo (no un módulo de clase esta vez, solo un módulo "regular"). Pegar el código siguiente en el módulo:
Option Explicit
Function PopulateArray() As Collection
Dim clnWlis As Collection
Dim wli As WorkLogItem
'Put some data in the collection'
Set clnWlis = New Collection
Set wli = New WorkLogItem
wli.TaskID = 1
wli.PersonName = "Fred"
wli.HoursWorked = 4.5
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 2
wli.PersonName = "Sally"
wli.HoursWorked = 3
clnWlis.Add wli
Set wli = New WorkLogItem
wli.TaskID = 3
wli.PersonName = "Fred"
wli.HoursWorked = 2.5
clnWlis.Add wli
Set PopulateArray = clnWlis
End Function
Sub TestGetHoursWorked()
Dim pwl As ProcessWorkLog
Dim arrWli() As WorkLogItem
Set pwl = New ProcessWorkLog
Set pwl.WorkLogItems = PopulateArray()
Debug.Print pwl.GetHoursWorked("Fred")
End Sub
En el código anterior, PopulateArray()
simplemente crea una colección de WorkLogItem
. En su código real, puede crear una clase para analizar sus hojas de Excel o sus objetos de datos para llenar una colección o una matriz.
El código TestGetHoursWorked()
simplemente muestra cómo se usaron las clases. Observa que ProcessWorkLog
se crea una instancia como un objeto. Después de que se crea una instancia, una colección de WorkLogItem
se convierte en parte del objeto pwl
. Usted nota esto en la línea Set pwl.WorkLogItems = PopulateArray()
. A continuación, simplemente llamamos a la función que escribimos que actúa sobre la colección WorkLogItems
.
¿Por qué es esto útil?
Supongamos que sus datos cambian y desea agregar un nuevo método. Supongamos que su WorkLogItem
ahora incluye un campo para HoursOnBreak
y desea agregar un nuevo método para calcularlo.
Todo lo que necesita hacer es añadir un alojamiento a WorkLogItem
así:
Private pHoursOnBreak As Double
Public Property Get HoursOnBreak() As Double
HoursOnBreak = pHoursOnBreak
End Property
Public Property Let HoursOnBreak(lHoursOnBreak As Double)
pHoursOnBreak = lHoursOnBreak
End Property
Por supuesto, tendrá que cambiar su método para poblar su colección (el método de muestreo que utilicé fue PopulateArray()
, pero probablemente deberías tener una clase separada solo para esto). Entonces sólo tiene que añadir el nuevo método a la clase ProcessWorkLog
:
Function GetHoursOnBreak(strPersonName As String) As Double
'Code to get hours on break
End Function
Ahora, si queríamos actualizar nuestro método TestGetHoursWorked()
para volver resultado de GetHoursOnBreak
, lo único que tendríamos que hacer lo que añadir la siguiente línea:
Debug.Print pwl.GetHoursOnBreak("Fred")
Si pasó una serie de valores que representaban sus datos, tendría que encontrar cada lugar en su código donde utilizó las matrices y luego actualizarlas en consecuencia. Si usa clases (y sus objetos instanciados), puede actualizar su código mucho más fácilmente para trabajar con cambios. Además, cuando permite que la clase se consuma de múltiples maneras (tal vez una función necesita solo 4 de las propiedades de los objetos, mientras que otra función necesitará 6), todavía pueden hacer referencia al mismo objeto. Esto evita tener múltiples matrices para diferentes tipos de funciones.
Para obtener más información, me gustaría altamente recomendamos obtener una copia de VBA Developer's Handbook, 2nd edition. El libro está lleno de excelentes ejemplos, mejores prácticas y toneladas de código de muestra. Si invierte mucho tiempo en VBA para un proyecto serio, vale la pena ver este libro.
+1, GRAN respuesta. Claro, fresco y muy útil para todos. –
+1 para el Manual del desarrollador de VBA! –
Todavía útil 5 años después, ¡gracias Ben! +1 de mi parte – FreeMan