September 13th, 2007
Most VB programmers, even those who’ve haven’t used VB.NET much, know that to create an object they invoke it by calling the class’s constructor using the New keyword. Those who’ve worked with VB.NET may know that there can be multiple constructors for a class and that the .NET Framework automatically builds a no-argument constructor behind the scenes for you at compile time if you don’t supply one. All of these constructors have a Public access modifier so that they can be created from outside the class. Sometimes, there will be cases where you only want one instance of a class in your application. This is where the Singleton Pattern comes into play.
Coding the Singleton Class
There are three steps to creating a simple Singleton class.
First, we will also want to have a module level Private Shared variable that holds the single instance we’re creating:
Public Class MySingleton Private Shared _thisInstance As MySingleton End Class
Next, we want to create a single constructor method with a Protected access modifier, like so:
Public Class MySingleton Private Shared _thisInstance As MySingleton Protected Sub New() 'initialization code goes here End Sub End Class
This prevents .NET from creating a default Public constructor and also prevents any caller from creating their own instance of the object. However, by using Protected, the class can still be subclassed if you need to do this.
Lastly, we want to create a Shared accessor method for the class. It would look like this:
Public Class MySingleton Private Shared _thisInstance As MySingleton Protected Sub New() 'initialization code goes here End Sub Public Shared Function GetSingleton() As MySingleton ' ' initialize object if it hasn't already been done ' If _thisInstance Is Nothing Then _thisInstance = New MySingleton End If ' ' return the initialized instance ' Return _thisInstance End Function End Class
Since this ‘get’ routine is Shared it can be called without having an instance of the object, as seen here.
Dim TestStuff As MySingleton = MySingleton.GetSingleton Dim MoreStuff As MySingleton = MySingleton.GetSingleton
In this example both TestStuff and MoreStuff are the same object instance, just with different names. That concept seems a bit confusing at first but don’t let that throw you. Just keep in mind that no matter how many variables you use to hold an instance of your Singleton class, it is actually always the same instance.
When Should You Use the Singleton Pattern?
A common place to use this pattern is with forms. You can easily make a form a Singleton class by following the steps above. The only thing you might want to override the OnClosing event to keep the form open but hidden, like so:
Protected Overrides Sub OnClosing(ByVal e As System.ComponentModel.CancelEventArgs) e.Cancel = True Me.Hide() End Sub
This technique with forms allows you to insure that only a single instance of a particular form is open at once. This is handy for search forms, certain kinds of pop-ups, and other forms commonly used throughout the application.
Using a Singleton is effective in situations where you need to prevent multiple copies of an object. For example, if you had a device driver for a device that only allowed a single connection at a time, a Singleton would be a good solution.
Another use would be in situations where you wanted to cloak the actual instantiation process or otherwise limit usage of a component. I’ve seen this used for proprietary classes and controls in add-on tools where the programmer wanted to hide initialization details from purchasers or limit trial period users.
There are also some drawbacks to using Singletons as well.
First, they can be a pain for other developers to work with. They’re expecting to use a New call but instead have to use a custom initializer. This can be annoying if there isn’t a good and well documented reason behind it. So, always consider your fellow developers when you implement the Singleton pattern.
Another thing to consider is that you may lose some flexibility in how and when the internal object is created based on how the program runs. This is particularly important in classes and components you provide beyond your own applications. Once again, consider other developers.
Using this pattern can lead to some of the problems associated with global variables. Like Globals, it can make a program harder to debug since state changes can come from anywhere. Because of this, I recommend avoiding putting stateful variables in these classes. Also, simply replacing your global variables with a Singleton class isn’t considered a good design practice. It only gives you the illusion of being object oriented. Avoid using this pattern this way.
I hope this introductory overview has been helpful to you. If you have any thoughts or questions on this topic, please feel free to leave me a comment.
Entry Filed under: VB.NET Tutorials
Rate This Article: