Singleton Design Pattern

The Singleton Design Pattern is one of the creational design patterns. Its primary intent is to ensure that a class has only one instance and provides a global point of access to that instance. Singleton ensures that only one object is created, even if multiple clients try to instantiate it.

Scenario Where Singleton is Required

Singleton is useful in situations where only one instance of a class should exist throughout the application's lifecycle. Common scenarios include:

Different Types of Singleton Design Patterns

1. Eager Initialization Singleton

In eager initialization, the Singleton instance is created at the time of class loading. This is the simplest form of Singleton, and the instance is created irrespective of whether it is needed or not.

Code Example:


    public class EagerSingleton {
        private static final EagerSingleton instance = new EagerSingleton();
  
        private EagerSingleton() {
            // Private constructor to prevent instantiation
        }
  
        public static EagerSingleton getInstance() {
            return instance;
        }
    }
    

Pros:

Cons:

2. Lazy Initialization Singleton

Lazy initialization defers the creation of the Singleton instance until it is requested. This can help in situations where the instance is resource-heavy or costly to create, and you want to delay its creation until necessary.

Code Example:


    public class LazySingleton {
        private static LazySingleton instance;
  
        private LazySingleton() {
            // Private constructor
        }
  
        public static LazySingleton getInstance() {
            if (instance == null) {
                instance = new LazySingleton();
            }
            return instance;
        }
    }
    

Pros:

Cons:

3. Breaking Singleton with Reflection

The Singleton pattern can be broken using reflection because reflection allows the private constructor to be accessed, thus bypassing the Singleton mechanism.

Code Example:


    import java.lang.reflect.Constructor;
  
    public class ReflectionSingletonBreaker {
        public static void main(String[] args) throws Exception {
            EagerSingleton instanceOne = EagerSingleton.getInstance();
  
            Constructor constructor = EagerSingleton.class.getDeclaredConstructor();
            constructor.setAccessible(true); // Bypassing private constructor
            EagerSingleton instanceTwo = constructor.newInstance();
  
            System.out.println(instanceOne == instanceTwo); // Prints false, breaking Singleton
        }
    }
    

Pros:

Cons:

4. Thread-Safe Singleton

In multi-threaded environments, lazy Singleton can lead to multiple instances being created. Thread-safe Singleton ensures that even if multiple threads access the getInstance() method simultaneously, only one instance is created.

Code Example:


    public class ThreadSafeSingleton {
        private static ThreadSafeSingleton instance;
  
        private ThreadSafeSingleton() {
            // Private constructor
        }
  
        public static synchronized ThreadSafeSingleton getInstance() {
            if (instance == null) {
                instance = new ThreadSafeSingleton();
            }
            return instance;
        }
    }
    

Pros:

Cons:

Pros and Cons of Singleton Design Pattern

Pros:

Cons: