WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

VB.NET OOP Part 3: The Singleton Pattern

by Budi Kurniawan
11/11/2002

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
By Budi Kurniawan, Ted Neward

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 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.

  1. Save the code in Listing 1 in the SingletonForm.vb file.
  2. Open a command prompt.
  3. Change directory to the directory where SingletonForm.vb resides.
  4. 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.

  1. Save the code in Listing 2 in the MyForm.vb file in the same directory in which the SingletonForm.dll file resides.
  2. 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

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

SingletonForm instance

Budi Kurniawan is a senior J2EE architect and author.


Return to ONDotnet.com