Beginners and seasoned object-oriented programmers know that they create an
instance of a class by invoking the class' constructor preceded by the New
keyword. For example, the following code constructs an instance of class
MyClass by calling its no-argument constructor:
New MyClass()
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 Ctrl-F
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.)
|
Related Reading
VB.NET Core Classes in a Nutshell |
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.
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
shared GetInstance method, and there is also a shared variable called
myInstance (of type SingletonForm). The 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 myInstance.
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
following snippet.
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 Form class,
you can call its Show method.
myForm.Show()
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.
vbc /t:library /r:System.dll,System.Windows.Forms.dll SingletonForm.vb
The result of the compilation is a DLL file named SingletonForm.dll.
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.
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 SingletonForm.
Figure 2: The SingletonForm instance
Budi Kurniawan is a senior J2EE architect and author.
Return to ONDotnet.com
Copyright © 2009 O'Reilly Media, Inc.