A factory is where things are made and, in object-oriented programming, a factory is where objects are made – factories encapsulate object creation. In a factory, an instance of a class is created, its state set and then it’s returned to the caller. A simple factory in VBA may look like:
Public Function Factory(ByRef className As String) As Object
Select Case className
Case "Cat": Set Factory = New Cat
Case "Dog": Set Factory = New Dog
Case Else: Err.Raise Number:=..., Description:="Factory does not recognise this className."
Here we see:
1. The factory is a method that returns a value (ie. a Function);
2. It uses the string value ‘className’ to determine the class to instantiate;
3. Although an object of type ‘className’ is created, the factory returns it with a type ‘Object’.
4. If the factory doesn’t recognise the className, it throws an error.
Note that although the factory is creating an object that corresponds to ‘className’, it is being returned as an object of type ‘Object’. Since all objects derive from ‘Object’, they can be cast as such. Since a VBA function can only return one object type and we want our factory to be able to create objects of many different types, we have it return ‘Object’ to the caller. The caller can then re-cast the object to be of the proper type (for it was the caller that asked for that particular type).
To illustrate this Cast/Re-cast situation, assume ‘Cat’ is defined as:
Public Sub MakeNoise()
ie. the class contains just one public method. If you run this code in a Standard Module:
Public Sub Test()
Dim o As Object, c As Cat
Set o = New Cat
Set c = obj
You’ll see that, irrespective of whether we use the reference ‘o’ or the reference ‘c’, the call(s) to MakeNoise produce the same result. What you’re really seeing here is that ‘Object’ and ‘Cat’ are both interfaces to the class ‘Cat’. The advantage of the factory returning an ‘Object’ is that the factory can be used to instantiate and return any class, since all classes conform to the ‘Object’ interface. In fact, it is better to say any object that can be created in the factory must conform to a given interface. In the above example, that interface was ‘Object’ and, since all classes conform to ‘Object’, the factory could return an instance of either ‘Cat’ or a ‘Dog’.
Of course you aren’t limited to just ‘Object’. You can define your own Interface, define classes that implement that interface, and then create a factory that can only create instances of objects that conform to that interface. Since you’re using Interfaces, this type of factory is called ‘Polymorphic’ due to the fact that any object returned to the caller will have the same set of fields, properties and methods (procedures and functions) as defined by the Interface. Hence, the calling code can make use of those fields, properties and methods ‘agnostically’, ie. without knowing the true, underlying type of object it is working with. Polymorphism at work.
The Cat/Dog factory illustrated at the very beginning of this post is an example of a Simple Factory. ‘Simple’ in the sense that the list of possible objects is defined at design time by the developer. If a new class is subsequently added, then the factory code needs to be updated as well.
It is possible, in VBA, to create a more complex factory that scans the VBComponents collection at runtime to determine what classes are available and what interfaces they implement, and then uses this data to create the actual code contained in the factory (Monkey Patching in the extreme). However, the ability to write code at runtime is a security risk (this is how VBA viruses propagate) and in most enterprise environments a Developer’s ability to do so is removed. Although it is by no means the ‘coolest’ on the spectrum, the Simple Factory illustrated above, is the easiest to understand and implement for the first-time OO VBA Developer. I will save discussion of the complex factory for another blog post.
The only remaining consideration is how you implement your Simple Factory. As shown, the ‘factory’ is simply a Function. Therefore, it can be housed in either a Standard Module or a Class Module. Given its importance, I tend to put it in its own module – either a Standard module or a Static Class Module (see my earlier blog on Static Classes in VBA). There are no rules, of course, and it is entirely down to personal preference – just remember that the simpler your code is to understand, the easier it will be to support in the future.