🔍 What is the Singleton Design Pattern?

The Singleton Pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to it.


✅ When Should You Use It?

  • To manage shared resources like database connections, thread pools, caches, logging, etc.
  • When you want to restrict object creation to only one instance throughout the application lifecycle.

🧠 Real-World Analogy

Think of the President of a country. There is only one President at any given time. If anyone tries to create another one, it should return the same instance 👑.


🧱 Structure

We’ll cover 4 variations of Singleton in Java:

  1. Basic Singleton (Lazy Initialization)
  2. Thread-Safe Singleton (Synchronized)
  3. Bill Pugh Singleton (Best Practice)
  4. Enum Singleton (Most Robust)

✅ 1. Lazy Initialization (Not Thread-Safe)

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {} // private constructor

    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

Not thread-safe. Two threads may create two instances.


✅ 2. Thread-Safe Singleton (Synchronized)

public class ThreadSafeSingleton {
    private static ThreadSafeSingleton instance;

    private ThreadSafeSingleton() {}

    public static synchronized ThreadSafeSingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }
}

Thread-safe, but slower due to synchronization.


✅ 3. Bill Pugh Singleton (Recommended)

public class BillPughSingleton {
    private BillPughSingleton() {}

    private static class Holder {
        private static final BillPughSingleton INSTANCE = new BillPughSingleton();
    }

    public static BillPughSingleton getInstance() {
        return Holder.INSTANCE;
    }
}

Thread-safe, fast, and lazy-loaded. Best practice in most cases.


✅ 4. Enum Singleton (Robust & Safe)

public enum EnumSingleton {
    INSTANCE;

    public void doSomething() {
        System.out.println("Doing something from Enum Singleton");
    }
}

✅ Simplest and safest, handles serialization, reflection, and thread safety.


💻 Client Code

public class SingletonDemo {
    public static void main(String[] args) {
        LazySingleton s1 = LazySingleton.getInstance();
        LazySingleton s2 = LazySingleton.getInstance();
        System.out.println("Same LazySingleton? " + (s1 == s2)); // true

        BillPughSingleton b1 = BillPughSingleton.getInstance();
        BillPughSingleton b2 = BillPughSingleton.getInstance();
        System.out.println("Same BillPughSingleton? " + (b1 == b2)); // true

        EnumSingleton.INSTANCE.doSomething();
    }
}

🧪 Output:

Same LazySingleton? true
Same BillPughSingleton? true
Doing something from Enum Singleton

⚙️ UML Diagram (Text Format)

+--------------------+
    |   SingletonClass   |
    +--------------------+
    | -instance: static  |
    | -constructor()     |
    +--------------------+
    | +getInstance(): SingletonClass |
    +--------------------+

🧑‍🏫 Key Takeaways

  • Singleton ensures only one instance exists.
  • Use Bill Pugh or Enum versions in production.
  • Useful for centralized services like logging, config, DB access.

🚀 Up Next for Day 4: Want to explore Decorator, Strategy, or Adapter?

Let me know your pick, and I’ll keep the clean breakdown + rich Java code style coming!