The Singleton Pattern: Ensuring One & Only One Instance

alpharithms fallback 1

The Singleton is a design pattern used in object-oriented programming that ensures only a single instance of an object exists within a system at any given time. The singleton is useful for things like loggers, state managers, and other objects that need to be globally accessible across an application.

The Singleton was outlined in the now infamous Design Patterns: Elements of Reusable Object-Oriented Software (GoF) and has been formally used in software design for decades. Its implementation is simple, involving a single class, but the complexities of its role within software is complex—to say the least. In this article, we’ll cover how to implement the Singleton and some common use cases. First, let’s consider how the Gang of Four originally described it.

What is the Singleton?

As described in the Design Patterns book, the purpose of the Singleton is described as such:

Ensure a class only has one instance, and provide a global point of access to
it.

This is pretty straightforward but doesn’t lend much in way of motivation for such a pattern. Fortunately, Movitation happens to be the name of the next section in the book, which elaborates as such:

It’s important for some classes to have exactly one instance. Although there can
be many printers in a system, there should be only one printer spooler. There
should be only one file system and one window manager 

The book continues by describing the common use-case of which the Singleton offers a robust alternative:

How do we ensure that a class has only one instance and that the instance is easily accessible? A global variable makes an object accessible, but it doesn’t keep
you from instantiating multiple objects.

There it is: avoiding duplicate objects while providing global access to certain variables. Global variables are inherently dangerous, regarded by many as code smells, and can easily alter a system in unforeseen ways.

When is the Singleton Used?

The Singleton pattern is clearly useful but its overuse can provide as much trouble as its correct use can provide benefit. Knowing the implications of the Singleton, especially the circumstances in which it’s best suited, can help avoid potentially disastrous conflicts and bugs. In the original outline of the Singleton, the Gang of Four describe the most appropriate conditions in which the Singleton can be used:

  1. There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point;
  2. When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code.

Two conditions—simple enough, right? The Singleton can cause some issues when used improperly, or even properly (unit testing, parallel testing, added dependencies, etc.) Nonetheless, the benefits still outweigh the potential downsides in many cases. Let’s consider some of the more prominent Singleton benefits.

Benefits of the Singleton Pattern

In the Design Patterns book, the Gang of Four outlines several obvious benefits of the Singleton. These benefits explained as high-level concepts, do not guarantee conflict-free implementation by any means.

Rather the following benefits are meant as guidelines to help developers understand the potential benefits the Singleton has to offer when used appropriately.

  1. Controlled Access to a single instance;
  2. Reduction in application Name Space;
  3. Extensible by subclassing;
  4. Can permit additional instances;
  5. Relative flexibility

These benefits of the Singleton pattern make it sound like a sure-fire winner. However, one might notice that there isn’t a lot of direction on just how these benefits might be realized through implementation. Let’s consider what the implementation of a Singleton class actually looks like.

Implementing the Singleton

singleton pattern uml diagram overcoded

In terms of class complexity, the Singleton is pretty straightforward to implement. No interfaces, no inheritance, nothing fancy but ensuring that an attribute for holding a class instance and method for accessing that instance. In fact, the UML representation of a Singleton doesn’t offer much insight at all as to the nature of its implementation! Let’s look at some code:

/**
 * A basic implementation of the Singleton pattern such 
 * that only a single instance of the class may be 
 * present in the application.
 */
public class Singleton {

    // A private static method that holds the 
    // single instance of the Singleton, if 
    // one has been instantiated anywhere.
    private static Singleton _instance = null;

    /**
     * Private constructor to prevent instantiation of 
     * Single objects from anywhere other than this Class.
     */
    private Singleton(){}

    /**
     * Method to return the current instance of the Singleton
     * class if one has been instantiated or, if not, create
     * and return the new one.
     * @return Singleton - the single globally-accessible instance
     */
    public static Singleton getInstance(){
        if(_instance == null){
            _instance = new Singleton();
        }
        return _instance;
    }
}

In the code above, you may notice several oddities characterized by static methods, private constructors, and Factory-Pattern-like instantiation. These are the basic requirements for the Singleton pattern to ensure it behaves as intended. Let’s consider each method and attribute a bit more.

Static Attribute: _instance

The _instance attribute is defined as both static and private. This is a strange combination—given that static accessors are generally defined as public and would default to package-private if no accessor were specified (the same as classes in Java).

The use of a private static variable here ensures that only the Singleton class has access. Given this is the attribute that will hold a reference to our single global instance, we don’t want other class objects to have direct access.

Private Constructor

The Singleton’s sole constructor method is private which means no other class object can create a new instance via conventional means as new Singleton();. Instead, the privatization of the constructor ensures only the Singleton class can create a new instance—with full control of the means of how such is done.

The getInstance Method

This is the heart and soul of the Singleton and determines when to create a new Singleton instance and when to return an existing one. If another class instance calls the getInstance method it will be given the existing Singleton instance, if it exists, or will trigger the Singleton class to create a new class instance and return that.

The Singleton in Action

With a few additions to the code above we can see how the Singleton class behaves. Consider the following additions:

// A variable to hold a String message
String message = "Hello, my name is Singleton.";

/**
 * Getter method to return instance message
 * @return String - Message currently held by Singleton
 */
public String getMessage() {
    return message;
}

/**
 * Setter method to change the current message
 * @param message String - value to change the message to.
 */
public void setMessage(String message) {
    this.message = message;
}

This code, inserted just below our Singleton class’ declaration, provides a new String variable in which a message is stored. This message is accessed via standard getter and setter methods. We can demonstrate the functionality of the class with the following code:

/**
 * A simple example driver to illustrate the basic operations of
 * the Single class.
 */
public static void main(String[] args) {

    // Create a new Singleton object via static method
    Singleton singleton = Singleton.getInstance();

    // Print the message to standard output
    System.out.println(singleton.getMessage());

    // Create a new singleton object
    Singleton singletonTwo = Singleton.getInstance();

    // Create a unique message for the second Singleton
    singletonTwo.setMessage("Hello, my name is SingletonTwo");

    // Print the message of the second Singleton
    System.out.println(singletonTwo.getMessage());

    // Print the message of the first Singleton again (it changed!)
    System.out.println(singleton.getMessage());

}

This code does the following actions:

  1. Requests an instance of the Singleton class, generating our first instance;
  2. Requests another instance of the Singleton class, getting the first instance in return;
  3. Sets the message of the second Singleton variable
  4. Prints the message of both the first and second Singleton variable.

This results in the following output being printed to the console screen:

Hello, my name is Singleton.
Hello, my name is SingletonTwo
Hello, my name is SingletonTwo

On line one, we see the default message encoded into the Singleton class. On the second line, we see the new message we’ve set via the singletonTwo object. On the third line, we attempt to print out the initial message from our first singleton object. However, this time we get the message from the singletonTwo object!

But why? When we create the singletonTwo object we are really just given the same instance as assigned in the first singleton variable. So when we update the message of the second object, we’re really updating the message of both—because they reference the same single instance!

Final Thoughts

The Singleton Pattern is one that is implemented across many application systems across many different programming languages. It provides convenient access on a global scale while limiting namespace, is extensible, and can even allow for a controlled variable number of instances if desired.

The Singleton is used in applications for logging, game environments to help manage scenes, and many other applications. There’s a growing conversation focused on the overuse and/or misuse of the Singleton pattern. I think there exists the possibility to misuse any design pattern and the Singleton is no exception. Knowing what it is, when others use it, and how to implement it can help determine if it is appropriate for a given application.

Note: A complete version of the code from this article is available via Github here.

Zαck West
Full-Stack Software Engineer with 10+ years of experience. Expertise in developing distributed systems, implementing object-oriented models with a focus on semantic clarity, driving development with TDD, enhancing interfaces through thoughtful visual design, and developing deep learning agents.