This article refers to design patterns, pointers and objects (discussed in the background section of this article), and classes. Make sure you’re familiar with these issues before reading on.
We begin our exploration of the word of Design Patterns with one of the simplest patterns – the Singleton. The Gang of Four eloquently summarize the intent of the Singleton pattern as follows: "Ensure a class only has one instance, and provide a global point of access to it". We can illustrate the pattern’s concept with an example.
Background and motivation
Imagine having a script which accesses a database, or writes data to an external excel file. In order to accomplish these tasks, the script must create and utilize auxiliary objects that connects to the database or the file (e.g. a FileSystemObject, an Excel.Application or an ADO object), and perform various tasks.
If we allow our script to create these objects freely, we risk ending up with extremely inefficient code, or even worse, a script which produces errors and even breaks the system it tests. Just imagine the time wasted by creating an Excel COM object every time you report an event, or creating multiple database connection to the application’s backbone. These objects might even lock the relevant resources, thereby failing the script in unpredictable ways.
So it’s clear we should control the manner in which certain objects are created and managed throughout our scripts. This is exactly the context in which the Singleton pattern operates – it allows us to freely ask for these objects, but ensures that only one central instance of each object will be actually created and used.
Constraints and workarounds
As I’ve stated in the introduction article, Design Patterns are "meant for" object oriented programming languages. As a result, we’ll have to "downgrade" the patterns to fit into a VBScript and QTP context. As we’re about to see, this "downgrading" will be especially dominant for the Singleton pattern.
"Real" programming languages have static (AKA shared) variables and sub-procedures, and they play a critical part in any implementation of the Singleton Pattern. In case you’re unfamiliar with the terms – don’t worry. VBScript doesn’t support static elements anyway (neither does JavaScript), so we’ll have to find some workaround that will allow us to implement the Singleton pattern in VBScript without them.
I will present several implementations of the Singleton pattern, with growing complexity and usability. Some implementations may fit a certain situation better than others (not necessarily the most sophisticated ones), but they all track the same logical frame of mind.
VBScript implementations
The most basic VBScript implementation of this pattern relays on a global variable which holds the required object (it serves as a degraded form of static variable). New objects are created only if the global variable is "empty".
Public oExcel 'Announce the global variable
Dim bAleadyInit 'Will tell us if the object requires initialization
'Check if the object is already initialized
bAlreadyInit = False
If IsObject(oExcel) = True Then
'The object was once initialized
If Not oExcel is Nothing Then
'The object is "alive"
bAlreadyInit = True
End If
End If
'Create a new instance only if needed
If bAlreadyInit = False then Set oExcel = CreateObject("Excel.Application")
oExcel.Whatever 'Use the object
Now, this will work fine, but will produce tons and tons of duplicate code. So the next step will be to pack the duplicate code in a dedicated Sub-procedure:
Sub InitExcel
Dim bAleadyInit 'Will tell us if the object requires initialization
bAlreadyInit = False
If IsObject(oExcel) = True Then
'The object was once initialized
If Not oExcel is Nothing Then
'The object is "alive"
bAlreadyInit = True
End If
End If
'Create a new instance only if needed
If bAlreadyInit = False Then Set oExcel = CreateObject("Excel.Application")
End Sub
InitExcel 'Initialize the object (if needed)
oExcel.Whatever 'Use the object
These implementations will work, but they are poorly designed. The code is too coupled – both the "client" (i.e. the flat code) and the procedure relay on the global variable, which means that if we ever change the global variable name or implementation we’ll be in deep trouble (it will force us to run through the code and correct all the oExcel reference). In order to solve this we could change our procedure to a function, and return a direct reference to the initialized object. This way the strong-coupling is broken, and the client (i.e. the flat code) doesn’t care where the reference originated.
Function GetExcel
Dim bAleadyInit 'Will tell us if the object requires initialization
bAlreadyInit = False
If IsObject(oExcel) = True Then
'The object was once initialized
If Not oExcel is Nothing Then
'The object is "alive"
bAlreadyInit = True
End If
End If
'Create a new instance only if needed
If bAlreadyInit = False Then Set oExcel = CreateObject("Excel.Application")
'Return a reference to the Singleton object
Set GetExcel = oExcel
End Function
Set oExcelInstace = GetExcel 'Get the object
oExcelInstace.Whatever 'Use the object
But wait, what about all the little oExcelInstace variables we’ll create throughout our scripts? It seems that the new design creates many duplicate instances of the excel object. However, we must remember that these are just pointer-reference to a single excel object, which is only created once. They cost us near-to-no resources, and we can easily eliminate them at will. Even if we destroy all these pointers, the real excel object will endure as it is still referenced by our global oExcel variable:
Set oExcelInstace = GetExcel 'Get the object
oExcelInstace.Whatever 'Use the object
Set oExcelInstace = Nothing 'Destroy the pointer; the real object lives on
Singleton and wrapper classes
Up until now we’ve separated our objects from the Singleton mechanism. We had an excel object, and a separated function which took care of the excel object’s lifecycle for us (or functions if we want another function in charge of destroying the Singleton object at the end of the script). While this design has its benefits, it overlooks the fact that we usually wouldn’t want to use separate functions for managing and utilizing our auxiliary objects.
Imaging we had separate functions for writing to a certain sheet of an excel file, for reading data, for querying specific values, etc. Our code will scatter and lose cohesion over time. It will become un-encapsulated, messy and hard to read and maintain. Usually, a good solution for this problem would be writing a wrapper class that encapsulates all the relevant code for an object. Here’s an example for a skeleton to a wrapper class of an excel object:
Class ExcelWrapper
Private oExcelObject
Private Sub Class_Initialize
Set oExcelObject = CreateObject("Excel.Application")
End Sub
Private Sub Class_Terminate
oExcelObject.Quit
Set oExcelObject = Nothing
End Sub
Public Sub Open(sFileName)
'Code for opening the file
End Sub
Public Function GetSheetData(sSheet)
'Code for reading the sheet and returning it as an array
End Sub
'More functions that manipulate and use the object
End Class
We can now modify our wrapper to implement the Singleton pattern by changing the Class_Initialize procedure:
Class Excel
'Other class methods and variables
Private Sub Class_Initialize
Dim bAlreadyInit
bAlreadyInit = False
If IsObject(oExcel) = True Then
'The object was once initialized
If Not oExcel is Nothing Then
'The object has not been destroyed
bAlreadyInit = True
End If
End If
'Only create new object if needed
If bAlreadyInit = False Then Set oExcel = CreateObject("Excel.Application")
'Set the local class excel reference to the global Singleton object
Set oExcelObject = oExcel
End Sub
End Class
Set oExcelInstace = New ExcelWrapper
oExcelInstace.Open("Something")
We can create as many instances of the wrapper class as we’d like – they will all access a single excel object. In some cases the wrapper could be even more efficient – for example, if we always access the same file and sheet, the wrapper could open them in the class initialization phase. In which case, once we create a new instance of the wrapper, we know it’s immediately ready for read/write operations.
Since we want to encapsulate everything into our wrapper classes, we must implement a method that destroys the global excel object (as destroying the wrapper class only destroys the pointers to the global object). This method should be called only when the script ends, and the auxiliary object is no longer needed (i.e. not in the Class_Terminate procedure):
Class Excel
'Other class methods and variables
Public Sub Destroy
oExcel.Quit
Set oExcel = Nothing
End Sub
End Class
A QTP tweak
Shifting our focus from VBScript to QTP, we can replace the global variable with a better mechanism by using the QTP Environment object. Instead of polluting our code with unnecessary global variables, we can just use the following object creation code (either in a wrapper class or a function):
Dim bAleadyInit 'Will tell us if the object requires initialization
On Error Resume Next
bAlreadyInit = IsObject(Environment("Excel_Object"))
If Err.Number <> 0 Then bAlreadyInit = False 'Environment isn’t even initialized
On Error Goto 0
If bAlreadyInit = True Then
If Environment("Excel_Object") is Nothing Then bAlreadyInit = False
End If
If bAlreadyInit = False Then
Environment("Excel_Object") = CreateObject("Excel.Application")
End If
Conclusion and prelude to the Factory Pattern
The Singleton pattern can help manage the pesky details of our objects’ lifecycles. The motivation for using it is clear - there are situations in which unmanaged creation of objects can lead to script failures and application problems.
While the Singleton pattern is considered to be a simple pattern, its VBScript implementation tends to be complicated since the language lacks static operations support. I hope that presenting the different implementations in a progressive manner helped you to understand the motives and purposes in each implementation, and to track the pattern’s relatively simple logic, regardless of its technical complexities.
The next article in the series will explore one of the more powerful Design Patterns – the Factory Pattern. We will show how we can combine it with the Singleton pattern to further centralize our control over the script’s entities and objects.
As we’ll add more patterns to our toolbox, our power and understanding will grow, and we’ll be able to present far more realistic and meaningful examples. You’ll see that the combined power of the Singleton and Factory patterns is so great, that it will enable us unravel the heart of the ReporterManager project.
Posted in Design Patterns

Yaron Assa




March 29th, 2008 at 8:09 am
[…] This article refers to design patterns, pointers and objects (discussed in the background section of this article), and classes. Make sure you’re familiar with these issues before reading on. It would also be prudent to brush up on the Singleton Pattern. […]