VB.NET OOP Part 3: The Singleton Patternby Budi Kurniawan
Beginners and seasoned object-oriented programmers know that they create an
instance of a class by invoking the class' constructor preceded by the
keyword. For example, the following code constructs an instance of class
MyClass by calling its no-argument constructor:
You get one object each time a constructor is called. If you call a class' constructor three times, you get three instances of the class. Also note that even if you don't write a constructor in your class, the VB compiler creates a no-argument constructor in the absence of one. However, if a class does have a constructor, whether it is a no-argument constructor or one that accepts arguments, the VB compiler does not create a new one. Normally, these constructors have a public access modifier because they are meant to be invoked from outside of the class.
However, there are cases where you want to limit the number of instances of a
class to one. For example, recall that in Microsoft Word you can press
to display a Find dialog. However, for the whole life of Microsoft Word, there
can only be one Find dialog. If you press
Ctrl-F two times, there is still only
one Find dialog. Even when there are multiple documents open, there can only be
one Find dialog that works with any active document. Indeed, you don't need
more than one instance of the Find dialog. Having more than one will probably
complicate matters. (Imagine having multiple instances of the Find dialog while
editing a document in Microsoft Word.)
The Singleton pattern can be used for this purpose. This pattern is effective for limiting the maximum number of instances of a class to exactly one. In this case, if more than one object needs to use an instance of the Singleton class, those objects share the same Singleton class instance. A class that implements the Singleton pattern is called a Singleton class.
How do you write a Singleton class? Simply put: by creating a public shared method which is solely responsible for creating the single instance of the class. This also means that the client of the class should not be able to invoke the Singleton class' constructor, either. Because the absence of a constructor will make the compiler create a no-argument public constructor, a class applying the Singleton pattern has a private or protected constructor. Because the constructor is private or protected, there is no way the client can create an instance of that class by calling its constructor. The constructor is not accessible from outside of the class!
The question that arises then, if the only constructor cannot be accessed, is: how do we get an instance of that class, then? The answer lies in a shared (static, in C#) method in the class. As mentioned above, a Singleton class will have a shared method that calls the constructor to create an instance of the class and return this instance to the caller of the shared method. But isn't the constructor private? That's right. However, remember that the shared method is also in the same class; therefore, it has access to all members of the class, including the private members of the class.
You might ask the following question: "You can't create an instance of a class by calling its constructor, so how do you call the shared method (responsible for creating the single instance of the class) without having the class instance?" Note, though, that shared members of a class can be invoked without having an instance of that class. To limit the number of instances to one, the shared method has to check if an instance has been created before. If it has, it simply returns a reference to the previous created instance. If it has not, it calls the constructor to create one. It's as simple as that.
Creating the SingletonForm Class
As an example, consider a form, the class of which is called
SingletonForm, in Listing
1. This class represents a Singleton form.
Listing 1: A Singleton form
Imports System Imports System.Windows.Forms Imports System.ComponentModel Public Class SingletonForm : Inherits Form Private Shared myInstance As SingletonForm Private Sub New() Me.Text = "Singleton Form " & _ "[Creation Time: " & _ DateTime.Now.ToString() & "]" Me.Width = 450 Me.Height = 150 End Sub Protected Overrides Sub OnClosing _ (ByVal e As CancelEventArgs) e.Cancel = True Me.Hide() End Sub Public Shared Function GetInstance() As SingletonForm If myInstance Is Nothing Then myInstance = New SingletonForm() End If Return myInstance End Function End Class
First of all, notice that the class only has one constructor and its access
modifier is private. Secondly, to get an instance of that class, you have the
GetInstance method, and there is also a shared variable called
myInstance (of type
GetInstance method returns the
myInstance variable. The method checks if
myInstance is null (
Nothing) and if
yes, calls the constructor.
If myInstance Is Nothing Then myInstance = New SingletonForm() End If
The method then returns
To obtain a reference to the only instance of the
SingletonForm class, you
don't use its constructor. Instead, you call its
GetInstance method, as in the
Dim myForm As SingletonForm = SingletonForm.GetInstance()
Once you get the instance, you can call its public members just as you would a
normal class' object. For example, since
SingletonForm extends the
you can call its
Note that we override the
OnClosing method of the
Form class so that it does
not destroy the instance when the form is closed. Instead, it just hides it.
Protected Overrides Sub OnClosing(ByVal e As CancelEventArgs) e.Cancel = True Me.Hide() End Sub
To compile the
SingletonForm class so that you can use it in your application,
do the following steps.
- Save the code in Listing 1 in the SingletonForm.vb file.
- Open a command prompt.
- Change directory to the directory where SingletonForm.vb resides.
- Type the following and press Enter.
vbc /t:library /r:System.dll,System.Windows.Forms.dll SingletonForm.vb
The result of the compilation is a DLL file named SingletonForm.dll.
Using the SingletonForm Class
Now that you have a Singleton class, you can use it from your application. The
code in Listing 2 is a form class that has a button. When the button is
clicked, the application displays the
SingletonForm class instance.
Listing 2: Using the SingletonForm Class
Imports System Imports System.Windows.Forms Imports System.ComponentModel Imports System.Drawing Public Class MyForm : Inherits Form Private button1 As New Button() Private Sub New() InitializeComponent() End Sub Private Sub InitializeComponent() Me.Text = "Using SingletonForm" button1.Text = "Show SingletonForm" button1.Size = New Size(150, 40) button1.Location = New Point(20, 20) AddHandler button1.Click, AddressOf button1_Click Me.Controls.Add(button1) End Sub Private Sub button1_Click(ByVal sender As Object, _ ByVal e As EventArgs) ' Get the SingletonForm instance Dim singleton As SingletonForm = SingletonForm.GetInstance() singleton.Show() End Sub Public Shared Sub Main() Application.Run(New MyForm()) End Sub End Class
To compile the
MyForm class, do the following.
- Save the code in Listing 2 in the MyForm.vb file in the same directory in which the SingletonForm.dll file resides.
- From the previous command prompt, type the following:
vbc /t:winexe /r:System.dll,System.Windows.Forms.dll, System.Drawing.dll,SingletonForm.dll MyForm.vb
This results in the MyForm.exe file. Calling this executable will display a form with a button, as shown in Figure 1.
Figure 1: The MyForm form that uses SingletonForm
Clicking the button displays the
SingletonForm. Clicking the button several
times does not create multiple instances of Singleton. If you close the
SingletonForm, it's not disposed of, but only made hidden. The next time you click
the button in
MyForm again, the same instance will be displayed. You can prove
this by checking the creation time on the title bar of the
Figure 2: The SingletonForm instance
Budi Kurniawan is a senior J2EE architect and author.
Return to ONDotnet.com