OOP in VBA: Immutability & The Factory Pattern

If you’ve ever exported a VBA class module and opened it in Notepad, you’ve probably already seen this:
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 ‘True
END
Attribute VB_Name = “Class1”
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False

These attributes unlock the true OOP potential of VBA.

VB_PredeclaredId

You know how every UserForm comes with a “default instance” for free? That’s because user forms have this attribute set to True, and that instructs VBA to create a global-scope object named after the type, so you can do this:

MyForm.Show vbModal

Without even creating an instance of MyForm. That’s not very OOP though – in fact it’s pretty much anti-OOP, since by doing that you’re not creating any objects… So what’s the use of this attribute in an OOP discussion? Keep reading.

VBA classes are Public, not creatable. This means when you reference a VBA project, you can see and use the classes in that project, but you can’t create instances of them. You need a way to expose functionality to the referencing VBA project, to return instances of such a class. Oh sure, you could add a standard module and expose a public function that does it – but standard modules don’t quite encapsulate their members, and it’s up to the client code to properly qualify function calls (e.g. FactoryModule.CreateMyClass). A better option is to create a dedicated object whose sole responsibility is to create objects of a given type – enter the factory patern.

In OOP design patterns, factories are often combined with the Singleton pattern – after all, there only ever needs to be one single instance of a factory class. Given that the class can’t be created by the client code with the New keyword, that’s precisely what setting the VB_PredeclaredId attribute to True will do.

Example

Say you have a Car class, with Make, Model and Manufacturer properties. It wouldn’t make sense for any of these properties to be changed after they’re set, right?

Private Type TCar
    Make As Integer
    Model As String
    Manufacturer As String
End Type
 
Private this As TCar
Public Property Get Model() As String
    Model = this.Model
End Property
 
Friend Property Let Model(ByVal value As String)
    this.Model = value
End Property
 
'...other properties

 

The Friend access modifier makes the Model property immutable, because client code located outside the VBA project this Car class is defined in, simply won’t see the Property Let member. However a CarFactory class defined in the same VBA project can:

 Public Function Create(ByVal carMake As Integer, ByVal carModel As String, ByVal carManufacturer As String) As Car
     Dim result As New Car
     result.Make = carMake
     result.Model = carModel
     result.Manufacturer = carManufacturer
     Set Create = result
 End Function

Because this CarFactory class has a PredeclaredId, the referencing VBA code can do this:

 Dim myCar As Car
 Set myCar = CarFactory.Create(2016, "Civic", "Honda")

And then the myCar object can’t be turned into a 2014 Honda Fit – not even by accident.

Future versions of Rubberduck will make it easy to set a class’ PredeclaredId attribute, and might actually provide tools to automate the creation of factories.

Advertisements

4 thoughts on “OOP in VBA: Immutability & The Factory Pattern”

  1. Not to muddy the waters too much, but that’s not really a singleton. There can only ever be one instance of a singleton. PredeclaredId and GlobalNamespace just provide a default instance. You can create other named instances of you wish. Great write up. I’ve been meaning to write something like this for a while, you beat me to it.

    Like

    1. Not exactly a Singleton indeed, but as far as client/referencing code goes (assuming it’s a separate VBA project), it can’t be new’d up, so the default instance is the only instance that will ever be created – I’d call it VBA’s Singleton 😉

      Liked by 1 person

  2. It was not real clear to me what had been achieved until I read the code about 10 times. This is what I understand. A class factory creates objects with some properties that were set at the time of creation and can’t be changed later on by the code that uses the objects.

    I once failed a job interview on the what is a class factory question so I have been looking for a clear answer for a while.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s