I'm refactoring a VBA application to start making use of Class modules. For context, it is a userform to set some variables for a series of specific data cleaning operations. I've been looking into transferring values from userform objects to variables in subs of separate modules.
During my research I came across this answer for dealing with userforms. It highlights the Model-View-Presenter pattern. The "Model" part of the answer outlines some code that defines a Private Type group of variables within a new Class module.
However, I also read this article which claims "We can avoid using Class modules in VBA by declaring the Type statement. It does not need any string modules because we can embed it into existing modules, saving us space."
I feel like I should know when to apply using Type within a Class module and when to use Type to avoid creating a Class module but I just haven't faced the need before, so I'm stuck in making a decision for my own application. Can anyone separate the two approaches for me by explanation/example?
CodePudding user response:
UDT are particularly useful for interacting with various Win32 API libraries and functions; they define a memory space that holds a number of related values, and if you read/write binary files they make your life so much easier too.
The "need" to avoid creating a class module is artificial: it's what you need to do with the data that should drive what's in your project, not how badly the VBIDE organizes a project with many modules (there's a free & open-source add-in that can help with that).
A Public Type
can only be declared in a standard module, can only be passed ByRef
, and that's a problem when you need "instances" in an array or collection.
Other than grouping the values under a single identifier, there is no advantage in using a public UDT to store model properties over, say, having a bunch of global variables... which isn't inherently wrong in itself, just not an object-oriented approach to programming.
In OOP, we think in terms of objects - and we define objects using class modules. The fundamental OOP principles we want to adhere to are encapsulation and abstraction here... two things that global state/variables simply don't do.
By defining a model with a dedicated class, you are still free to have a global instance that anyone can manipulate from anywhere if you like:
'Module1
Option Explicit
Public GlobalModel As New MyModelClass
... but you are also free to scope it locally (the tighter the scope, the better!), and when the object goes out of scope, its encapsulated data gets freed as well:
'Module1
Option Explicit
Public Sub DoSomething()
Dim Model As MyModelClass
Set Model = New MyModelClass
With New SomeForm
Set .Model = Model
.Show
End With
'form manipulated model properties and is now closed
Debug.Print Model.SomeProperty
End Sub '<~ Model is no longer in scope, the data is gone
With a public UDT, the data is going to outlive its intended scope.
Side note about this:
[...] outlines some code that defines a Private Type group of variables within a new Class module.
The private UDT isn't necessary, but helps keeping things tidy; see this Q&A for more details.