
Introduction
This article is meant to illustrate a design concept in which a singleton is used to abstract one layer from the next in an N-tiered system. This is a general design concept illustration with an actual code based example. This article is also meant for intermediate to advanced programmers who understand VB.NET and some of the more advanced capabilities of the language and compiler.
Background
The Singleton
The first thing that you must understand to use this design technique is the concept of a singleton. A singleton is a class that is built in a way that prevents the creation of multiple instances of itself in memory.

As illustrated above, when using a normal class, each user would create an instance of it in memory. However, with a singleton, User One would create an instance of the class and then User Two would receive a handle to the same class. This decreases the amount of memory required as well as the processor time required for the call since the object does not have to be built.
Imports System.Runtime.CompilerServices
Public Class ImplementationLocator
Private Shared myInterfaceClass As ImplementationLocator
Private Sub New()
End Sub
<MethodImplAttribute(MethodImplOptions.Synchronized)> _
Public Shared Function GetInstance() As ImplementationLocator
If myInterfaceClass Is Nothing Then
myInterfaceClass = New ImplementationLocator
End If
Return myInterfaceClass
End Function
Public Function GetVINA(ByVal CarCode As String) As IVehicleQuery
Select Case CarCode
Case Constants.CarCodes.Chevy
Return New implChevyVehicleQuery
Case Constants.CarCodes.Ford
Return New implFordVehicleQuery
Case Constants.CarCodes.Dodge
Return New implDodgeVehicleQuery
Case Else
Return Nothing
End Select
End Function
End Class
There are three things required to create a singleton in VB.NET. You must first create a Private Shared
reference to the class. Do not use a New
constructor in this call. The second is you must hide the New
constructor from everyone except the class itself by declaring it Private
. The last thing you must do is create a function that will return the Private Shared
instance from the first step. This function must be Public Shared
. You must also synchronize the whole method (my preferred way of doing it), or use SyncLock
. If you decide to use SyncLock
, the function would look like this:
Dim objLock as Object
Public Shared Function GetInstance() As ImplementationLocator
If myInterfaceClass Is Nothing Then
SyncLock(objLock)
If myInterfaceClass Is Nothing Then
myInterfaceClass = New ImplementationLocator
End If
End SyncLock
End If
Return myInterfaceClass
End Function
The key portions of this code are the creation of an object to hold the lock and the fact that we check to see if myInterfaceClass
has been created just before the lock and just after the lock. This is due to threading problems and the unpredictable nature of OS sleep calls.
The Interface
An interface in .NET is similar to a class. Both declare properties, methods, and events. An interface, however, does not have any implementation in itself. In other words, an interface is nothing but a signature file. Those of you that know C would be semi-familiar with this. In C, you must declare the signature of all functions at the top of the file. A .NET interface simply takes these declarations and puts them in a separate file. A class can then implement an interface by implementing all of properties, methods, and events laid out in the interface. Generally, only Public
and Friendly
items are put in an interface.
Public Interface IVehicleQuery
Function GetModelByVIN(ByVal strVIN As String) As String
Function ValidateVIN(ByVal strVIN As String) As Boolean
End Interface
The Implementation
Now that there is an interface, there must be classes that implement it for it to be of any use. Here are three classes that implement IVehicleQuery
:
Public Class implFordVehicleQuery
Implements IVehicleQuery
Public Function GetModelByVIN(ByVal strVIN As String) _
As String Implements IVehicleQuery.GetModelByVIN
Return "Mustang"
End Function
Public Function Validate(ByVal strVIN As String) _
As Boolean Implements IVehicleQuery.ValidateVIN
Return True
End Function
End Class
Public Class implChevyVehicleQuery
Implements IVehicleQuery
Public Function GetModelByVIN(ByVal strVIN As String) _
As String Implements IVehicleQuery.GetModelByVIN
Return "Nova"
End Function
Public Function Validate(ByVal strVIN As String) _
As Boolean Implements IVehicleQuery.ValidateVIN
Return True
End Function
End Class
Public Class implDodgeVehicleQuery
Implements IVehicleQuery
Public Function GetModelByVIN(ByVal strVIN As String) _
As String Implements IVehicleQuery.GetModelByVIN
Return "Charger"
End Function
Public Function Validate(ByVal strVIN As String) _
As Boolean Implements IVehicleQuery.ValidateVIN
Return True
End Function
End Class
Note that just below the class declaration, we have an “Implements [Interface Name]
”. After each function, there is an “Implements [Interface Name].[Function Name]
”. You may additionally add other methods and properties that you choose. The only requirement is that you at least include all of the items defined in the interface.
Using the Code
The purpose of the singleton in this case is to return an implementation of an interface. The only thing that the UI layer needs to know is the interface. Any class that implements that interface can be returned to an object of type Interface
. It's easier to look at the code:
Private Sub btnLookup_Click_1(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnLookup.Click
If TextBox2.Text <> "" Then
Dim myCarCode As String
If RadioButton1.Checked Then
myCarCode = Constants.CarCodes.Chevy
ElseIf RadioButton2.Checked Then
myCarCode = Constants.CarCodes.Ford
Else
myCarCode = Constants.CarCodes.Dodge
End If
Dim objVehicleQuery As IVehicleQuery
objVehicleQuery = ImplementationLocator.GetInstance().GetVINA(myCarCode)
If Not objVehicleQuery Is Nothing Then
TextBox1.Text = objVehicleQuery.GetModelByVIN(TextBox2.Text)
End If
Else
MessageBox.Show("Please enter a VIN", "No VIN Entered")
End If
End Sub
The important pieces of code in the above example are:
Dim objVehicleQuery As IVehicleQuery
objVehicleQuery = ImplementationLocator.GetInstance().GetVINA(myCarCode)
If Not objVehicleQuery Is Nothing Then
TextBox1.Text = objVehicleQuery.GetModelByVIN(TextBox2.Text)
End If
First, an object is made of type IVehicleQuery
. Then, we get an instance of the singleton using the GetInstance
method. From the returned object, we call the GetVINA()
method, passing it myCarCode
. The object returned depends on the value of myCarCode
. As long as the object implements IVehicleQuery
, it is a legal operation.
Credits
Special thanks goes out to Jeff Corn and David Shelton for introducing the concept to me.
History
None to date.