ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Using the Singleton Pattern

by Budi Kurniawan
08/27/2003

The Singleton pattern is one of the simpler design patterns in the book Design Patterns: Elements of Reusable Object-Oriented Software. 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. In more advanced use, this pattern can also be used to manage exactly n instances of a class. This article introduces this pattern with a simple example and provides a real-world example by presenting the StringManager class in Tomcat, the most popular servlet container. All of the examples used in this article can be downloaded here.

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. Even if you don't write a constructor in your class, the compiler creates a no-argument constructor for you. However, if a class does have a constructor, whether it is a no-argument constructor or not, the 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

Tomcat: The Definitive Guide
By Jason Brittain, Ian F. Darwin

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? Simple: create a public static method that 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's 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 a client can create an instance of that class by calling its constructor. The constructor is not accessible from outside of the class!

If the only constructor cannot be accessed, how do we get an instance of that class? The answer lies in a static method in the class. As mentioned above, a Singleton class will have a static method that calls the constructor to create an instance of the class and return this instance to the caller of the static method. But isn't the constructor private? That's right. However, remember that the static 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 static method (responsible for creating the single instance of the class) without having the class instance?" Note, though, that static members of a class can be invoked without having an instance of that class. To limit the number of instances to one, the static 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.

A Simple Example

As an example, consider a class called SingletonFrame in Listing 1. This class is a Singleton class.

Listing 1. A Singleton class

package singleton;
import javax.swing.*;

public class SingletonFrame extends JFrame {
    private static SingletonFrame myInstance;

    // the constructor
    private SingletonFrame() {
        this.setSize(400, 100);

        this.setTitle("Singleton Frame. Timestamp:" +
            System.currentTimeMillis());

        this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    }

    public static SingletonFrame getInstance() {
        if (myInstance == null)
            myInstance = new SingletonFrame();

        return myInstance;
    }

}

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 static getInstance method, and there is also a static variable called myInstance (of type SingletonFrame). The getInstance method returns the myInstance variable. The method checks if myInstance is null and, if so, calls the constructor.

if (myInstance == null)
    myInstance = new SingletonFrame();
return myInstance;

The method then returns myInstance.

To obtain a reference to the only instance of the SingletonForm class, call the getInstance method, as in the following snippet.

SingletonFrame singletonFrame =
    SingletonFrame.getInstance();

Once you have an instance, you can call its public members just as you would a normal class's object. For example, since SingletonFrame extends the Frame class, you can call its setVisible method.

The MyFrame class in Listing 2 shows how to use the SingletonFrame class. MyFrame is a JFrame with two buttons. Clicking one of the buttons creates an instance of SingletonFrame. However, clicking either button again will return the same instance.

Listing 2. Using the SingletonFrame

package singleton;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class MyFrame extends JFrame {

    JButton jButton1 = new JButton();
    JButton jButton2 = new JButton();

    public MyFrame() {
        try {
            init();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    private void init() throws Exception {
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        jButton1.setText("Show Singleton Frame");
        jButton1.setBounds(new Rectangle(12, 12, 220, 40));
        jButton1.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(ActionEvent e) {
                jButton1_actionPerformed(e);
            }
        });

        jButton2.setText("Show the same Singleton Frame");
        jButton2.setBounds(new Rectangle(12, 72, 220, 40));
        jButton2.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(ActionEvent e) {
                jButton2_actionPerformed(e);
            }
        });

        this.getContentPane().setLayout(null);
        this.getContentPane().add(jButton1, null);
        this.getContentPane().add(jButton2, null);
    }

    void jButton1_actionPerformed(ActionEvent e) {
        SingletonFrame singletonFrame = SingletonFrame.getInstance();
        singletonFrame.setVisible(true);
    }

    void jButton2_actionPerformed(ActionEvent e) {
        SingletonFrame singletonFrame = SingletonFrame.getInstance();
        singletonFrame.setVisible(true);
    }

    public static void main(String[] args) {
        MyFrame frame = new MyFrame();
        frame.setSize(300, 250);
        frame.setVisible(true);
    }
}

Figure 1 shows MyFrame. If you click one of the buttons, the SingletonFrame will be displayed (Figure 2). Note the timestamp on the title of SingletonFrame.

the MyFrame frame
Figure 1. The MyFrame frame

the SingletonFrame
Figure 2. The SingletonFrame

Now close the SingletonFrame, then click a button on MyFrame and notice that you get the same timestamp, indicating that you get the same instance.

Now, let's look at the Singleton pattern used to maintain exactly n instances of a class.

Real-World Singleton Example: The StringManager Class in Tomcat

A large application such as Tomcat needs to handle error messages carefully. In Tomcat, error messages are useful for both system administrators and servlet programmers. For example, Tomcat logs error messages in order for system administrators to easily pinpoint any abnormality that has happened. For servlet programmers, Tomcat sends a particular error message inside of every javax.servlet.ServletException thrown so that the programmer knows what has gone wrong with a servlet.

Tomcat uses ResourceBundles to support localized (multilingual) error messages and store those error messages in a properties file, so editing them is easy. However, there are hundreds of classes in Tomcat. Storing all error messages used by all classes in one big properties file will easily create a maintenance nightmare. To avoid this, Tomcat allocates a properties file for each package. For example, the properties file for the org.apache.catalina.connector package contains all error messages that can be thrown from any class in that package.

Each properties file is handled by an instance of the org.apache.catalina.util.StringManager class. When Tomcat is run, there will be many instances of StringManager, each of which reads a properties file specific to a package. The base name for the ResourceBundle is LocalStrings, so properties files must be named "LocalStrings" plus the language code. For example, the default properties file will be LocalStrings.properties. The properties file containing messages in the German language is named LocalStrings_de.properties, for example.

When a class in a package needs to look up an error message in that package's properties file, it will first obtain an instance of StringManager. However, many classes in the same package may need a StringManager, and it is a waste of resources to create a StringManager instance for every object that needs error messages. The StringManager class was therefore designed so that an instance is shared by all objects inside a package. It is a Singleton class with multiple instances. The StringManager class is too long to list here, but it's easy to understand.

The only constructor in StringManager is private so that you cannot use the new keyword to instantiate it from outside the class. You get an instance by calling its public static method getManager, passing a package name. Each instance is stored in a Hashtable with package names as its keys.

private static Hashtable managers = new Hashtable();

public synchronized static StringManager getManager(String packageName) {
    StringManager mgr = (StringManager)managers.get(packageName);
    if (mgr == null) {
        mgr = new StringManager(packageName);
        managers.put(packageName, mgr);
    }
    return mgr;
}

To get an error message, use the StringManager class's getString method, passing a key. Here is the signature of one of its overloads:

public String getString(String key)

Pages: 1, 2

Next Pagearrow