Home > Articles > Programming > Java

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

Singleton

Pattern Properties

Type: Creational
Level: Object

Purpose

To have only one instance of this class in the system, while allowing other classes to get access to this instance.

Introduction

Once in a while, you need a global object: one that's accessible from anywhere but which should be created only once. You want all parts of the application to be able to use the object, but they all should use the same instance.

An example is a history list—a list of actions a user has taken while using the application. Multiple parts of the application use the same HistoryList object to either add actions a user has taken or to undo previous actions.

One way to achieve this is to have the main application create a global object, then pass its reference to every object that might ever need it. However, it can be very difficult to determine how you want to pass the reference, and to know up front which parts of the application need to use the object. Another drawback to this solution is that it doesn't prevent another object from creating another instance of the global object—in this case, HistoryList.

Another way to create global values is by using static variables. The application has several static objects inside of a class and accesses them directly.

This approach has several drawbacks.

  • A static object will not suffice because a static object will be created at the time the class loads and thus gives you no opportunity to supply any data before it instantiates.

  • You have no control over who accesses the object. Anybody can access a publicly available static instance.

  • If you realize that the singleton should be, say, a trinity, you're faced with modifying every piece of client code.

This is where the Singleton pattern comes in handy. It provides easy access for the whole application to the global object.

Applicability

Use the Singleton when you want only one instance of a class, but it should be available everywhere.

Description

The Singleton ensures a maximum of one instance is created by the JVM (not surprisingly, that's why it's called a singleton). To ensure you have control over the instantiation, make the constructor private.

This poses a problem: it's impossible to create an instance, so an accessor method is provided by a static method (getInstance()). That method creates the single instance, if it doesn't already exist, and returns the reference of the singleton to the caller of the method. The reference to the singleton is also stored as a static private attribute of the singleton class for future calls.

Although the accessor method can create the singleton, most of the times it is created as the class is loaded. Postponing the construction is only necessary if some form of initialization has to be done before the singleton is instantiated.

An example of a singleton is the president of the United States of America. At any given time there should only be one president. When the president of Russia picks up the red phone, he expects to get a handle to the current United States president.

Implementation

The Singleton class diagram is shown in Figure 1.6.

Figure 1.6 Singleton class diagram

To implement the Singleton pattern, you need:

  • Singleton – Provides a private constructor, maintains a private static reference to the single instance of this class, and provides a static accessor method to return a reference to the single instance.

The rest of the implementation of the Singleton class is normal. The static accessor method can make decisions about what kind of an instance to create, based on system properties or parameters passed into the accessor method (see the Pattern Variants section for this pattern).

Benefits and Drawbacks

Benefits and drawbacks include the following:

  • The Singleton is the only class that can create an instance of itself. You can't create one without using the static method provided.

  • You don't need to pass the reference to all objects needing this Singleton.

  • However, the Singleton pattern can present threading problems, depending upon the implementation. You must take care regarding control of the singleton initialization in a multithreaded application. Without the proper control, your application will get into "thread wars."

Pattern Variants

Pattern variants include the following:

  • One of the Singleton's often-overlooked options is having more than one instance inside the class. The benefit is that the rest of the application can remain the same, while those that are aware of these multiple instances can use other methods to get other instances.

  • The Singleton's accessor method can be the entry point to a whole set of instances, all of a different subtype. The accessor method can determine at runtime what specific subtype instance to return. This might seem odd, but it's very useful when you're using dynamic class loading. The system using the Singleton can remain unchanged, while the specific implementation of the Singleton can be different.

Related Patterns

Related patterns include the following:

  • Abstract Factory
  • Builder
  • Prototype

Example

Application users want the option of undoing previous commands. To support that functionality, a history list is needed. That history list has to be accessible from everywhere in the PIM and only one instance of it is needed. Therfore, it's a perfect candidate for the Singleton pattern.

Example 1.20 HistoryList.java 0

 1. import java.util.ArrayList;
 2. import java.util.Collections;
 3. import java.util.List;
 4. public class HistoryList{
 5.   private List history = Collections.synchronizedList(new ArrayList());
 6.   private static HistoryList instance = new HistoryList();
 7.   
 8.   private HistoryList(){ }
 9.   
10.   public static HistoryList getInstance(){
11.     return instance;
12.   }
13.   
14.   public void addCommand(String command){
15.     history.add(command);
16.   }
17.   
18.   public Object undoCommand(){
19.     return history.remove(history.size() - 1);
20.   }
21.   
22.   public String toString(){
23.     StringBuffer result = new StringBuffer();
24.     for (int i = 0; i < history.size(); i++){
25.       result.append(" ");
26.       result.append(history.get(i));
27.       result.append("\n");
28.     }
29.     return result.toString();
30.   }
31. }

The HistoryList maintains a static reference to an instance of itself, has a private constructor, and uses a static method getInstance to provide a single history list object to all parts of the PIM. The additional variable in HistoryList, history, is a List object used to track the command strings. The HistoryList provides two methods, addCommand and undoCommand to support adding and removing commands from the list.

  • + Share This
  • 🔖 Save To Your Account