Singleton Design Pattern

Singleton design pattern ensure that only one object of a class is created and it provides a way for other classes to access its only object directly without instantiate an object of the class. It is one of the simplest creational design patterns as it provides a way to create only one object of a class.

Sometimes, we want only one instance of a class like when only object is needed for centralized processing of any shared resources. Other examples where singleton classes are useful are "static configuration reader class", "Logger class", "Shared database handler" etc.

  • Singleton pattern ensure that only one instance of a class is created.
  • Single object should be available for use by all classes.
  • No class can create an instance(object) of singleton class using new operator.
In this tutorial, we will explore the Singleton Design Pattern in Java, discussing its structure, implementation methods and best practices to ensure a reliable and efficient use of the pattern.


Structure of the Singleton Design Pattern

The Singleton Design Pattern involves a single class, responsible for creating and managing its own instance. The key components of the pattern include:
  • Private Constructor : The class has a private constructor to prevent external instantiation.

  • Private Static Instance : The class contains a private static instance of itself.

  • Public Static Method : The class provides a public static method that returns the instance. If the instance doesn't exist, it is created; otherwise, the existing instance is returned.

Advantages of Singleton Design Pattern

  • Global Point of Access : To its services or resources, the singleton instance offers a global point of access. Because they can quickly retrieve the instance and use its methods, other classes can now interact with the singleton in a simpler manner.

  • Reduces Global Variable Use : By enclosing the instance inside the class, singletons offer an alternative to global variables. By doing this, the possible drawbacks of utilizing global variables—such as namespace pollution and accidental modifications—are reduced.

  • Single Instance :The Singleton pattern's main benefit is that it guarantees a class has just one instance. Because this instance is globally available, coordinating activities or sharing resources across various system components is simple.

  • Lazy Initialization : An instance is only created when it is first requested thanks to the Singleton pattern, which permits lazy initialization. This can be useful in situations where the object is not always required or where the object's instantiation requires a lot of resources.

  • Resource Sharing : Singletons come be handy in situations when a database connection pool, configuration settings, or a logging service are among the resources that several components of a system must share. The shared resource manager is the singleton instance.

  • Improved Memory Management : The Singleton pattern, which only has one instance, can aid in better memory management. There is only one instance of the class rather than several, which lowers memory usage and boosts system performance overall.

  • Prevents Unnecessary Instantiation : The pattern avoids needless instance creation by managing the instantiation process inside the singleton class. This can be important in situations when running several instances might result in unexpected behavior or inefficiencies.

Implementation of Singleton Design Pattern

The implementation of a singleton pattern is very simple as it involves only one class which is responsible for creating an static member of itself and the returning the reference to the static member. A Singleton class contains a private constructor, a static member of "Singleton" class and a public static method that returns a reference to the static member.

Steps to implement singleton pattern

Let, the name of singleton class is SingletonDemo.
  1. Define a private static member of "SingletonDemo" class. It will contain the reference of single object.
  2. Define all constructors of SingletonDemo class as private, so that any class cannot create instance of SingletonDemo using new operator.
  3. Define a public static factory method, that returns the static single instance of SingletonDemo class to the caller. Other classes can call this method to get an instance of SingletonDemo class.
Singleton Design Pattern UML Diagram

We can create single instance of a class either at load time(Early initialization) or later when it is required first time (Lazy initialization).

Singleton pattern program in Java using Early Initialization

Creating a Singleton class "SingletonDemo.java". It creates an object of SingletonDemo during load time.

public class SingletonDemo {
    // create an object of SingletonDemo
    // instance will be created at load time  
    private static SingletonDemo singleObj = new SingletonDemo();

    // A private constructor
    private SingletonDemo(){}

    // A public method to return singleton object to caller 
    public static SingletonDemo getInstance(){
        return singleObj;
    }

    public void doSomething(){
        System.out.println("Single Object of SingletonDemo class");
    }
}

Creating a Client class "SingletonDemoClient.java" which uses the only instance of SingletonDemo.

public class SingletonDemoClient {
    public static void main(String[] args) {
        // get singleton object of SingletonDemo class
        SingletonDemo instance = SingletonDemo.getInstance();

        // call some method of singleton object
        instance.doSomething();
    }
}

Output

Single Object of SingletonDemo class

Singleton pattern program in Java using Lazy Initialization

Creating a singleton class "SingletonDemoLazy.java", which creates an object when it is requested first time.

public class SingletonDemoLazy {
    private static SingletonDemoLazy singleObj = null;
    
    private SingletonDemoLazy(){ 
    }
    
    /*
      It will ceate an instance of SingletonDemo duirng first call, 
      otherwise returns existing object
     */
    public static synchronized SingletonDemoLazy getInstance() {
        if (singleObj == null) {
            singleObj = new SingletonDemoLazy();
        }
        return singleObj;
    }
}

Guidelines for Effective Singleton Pattern Implementation

  • Private Constructor : It is advisable to designate the constructor of your singleton class as private. This prevents external classes from generating instances and ensures that the singleton class maintains control over the instantiation process.

  • Static Instance : Employ a private static instance variable to store the unique instance of the class. This variable should be declared final to guarantee that it is only assigned once.

  • Thread Safety : Implement thread safety mechanisms to address situations where multiple threads attempt to access the singleton instance concurrently. This is vital for avoiding race conditions and preserving the singleton as a singular, exclusive instance.

  • Public Static Method : Endow the singleton instance with a public static method accessible from any part of the code. This method, when invoked, should either create the instance if it doesn't exist yet (Lazy Initialization) or return the pre-existing instance (Eager Initialization or Bill Pugh Singleton).

  • Enum Singleton : Joshua Bloch proposes using an enum to create a singleton, as outlined in "Effective Java." Enums inherently support the creation of a single, unique instance, and they handle concerns like serialization and reflection.

  • Dependency Injection : Explore the use of dependency injection frameworks to manage the lifecycle of singleton instances. This can streamline dependency handling and reduce code complexity.

  • Testing and Mocking : Design your singleton class with testability in mind. Avoid embedding dependencies in a rigid manner, and leverage dependency injection to facilitate testing. Additionally, provide a means to reset the singleton instance during testing.

  • Lazy Initialization with Holder Class : If opting for Lazy Initialization, contemplate adopting the Bill Pugh Singleton approach with a static inner helper class. This technique ensures thread safety without necessitating explicit synchronization in the getInstance method.

  • Keep it Simple : Aim for simplicity in your singleton implementation. Steer clear of unnecessary intricacies or variations unless they are genuinely essential for your specific use case.

  • Document the Singleton Intention : Clearly mention the purpose of your singleton class in documentation, elucidating why it must be a singleton and how it should be utilized. Such documentation aids other developers in comprehending the design rationale and employing the singleton appropriately.

Adhering to these guidelines facilitates the creation of a dependable and efficient implementation of the Singleton Design Pattern in Java. The pattern's capacity to furnish a solitary, universally accessible instance proves valuable in scenarios where coordination, control, or resource management holds paramount significance.

Related Topics
State Design Pattern
Factory Design Pattern
Mediator Design Pattern
Observer Design Pattern
Interpreter Design Pattern
List of Design Patterns