Join our FREE personalized newsletter for news, trends, and insights that matter to everyone in America

Newsletter
New

Understanding Singleton Design Pattern: A Simple Guide

Card image cap

What is Singleton Pattern?

Imagine you have a TV remote at home. You don't need 10 remotes for the same TV, right? One remote is enough for everyone in the family to use.

The Singleton pattern works the same way - it ensures that a class has only one instance and everyone uses that same instance.

Why Do We Need Singleton?

Think about these real-world examples:

  • Database connection - You don't want 100 connections to the same database
  • Printer - Multiple print jobs should go to the same printer
  • Settings/Configuration - Your app should have one set of settings, not multiple copies

Simple Example

Let's say we're building a Logger class to write logs to a file. We want only one logger in our entire application.

public class Logger {  
    // Step 1: Create a private static instance  
    private static Logger instance = null;  
  
    // Step 2: Make constructor private (no one can create new instances)  
    private Logger() {  
        System.out.println("Logger created!");  
    }  
  
    // Step 3: Provide a public method to get the instance  
    public static Logger getInstance() {  
        if (instance == null) {  
            instance = new Logger();  
        }  
        return instance;  
    }  
  
    // Your actual methods  
    public void log(String message) {  
        System.out.println("LOG: " + message);  
    }  
}  

How to Use It

public class Main {  
    public static void main(String[] args) {  
        // Get the logger instance  
        Logger logger1 = Logger.getInstance();  
        Logger logger2 = Logger.getInstance();  
  
        // Both are the same instance!  
        System.out.println(logger1 == logger2); // prints: true  
  
        logger1.log("Hello World!");  
        logger2.log("This is the same logger!");  
    }  
}  

The Problem with Above Code

The above code has a problem - it's not thread-safe. If two threads call getInstance() at the same time, we might create two instances.

Better Solutions

1. Thread-Safe Version

public class ThreadSafeLogger {  
    private static ThreadSafeLogger instance = null;  
  
    private ThreadSafeLogger() {}  
  
    // Add 'synchronized' keyword  
    public static synchronized ThreadSafeLogger getInstance() {  
        if (instance == null) {  
            instance = new ThreadSafeLogger();  
        }  
        return instance;  
    }  
}  

2. Eager Initialization (Recommended for Beginners)

public class EagerLogger {  
    // Create instance immediately when class loads  
    private static final EagerLogger instance = new EagerLogger();  
  
    private EagerLogger() {}  
  
    public static EagerLogger getInstance() {  
        return instance; // Just return the already created instance  
    }  
}  

3. Enum Singleton (Best Approach)

public enum LoggerEnum {  
    INSTANCE;  
  
    public void log(String message) {  
        System.out.println("LOG: " + message);  
    }  
}  
  
// Usage  
LoggerEnum.INSTANCE.log("Hello from enum singleton!");  

Advantages

Memory Efficient - Only one instance exists

Global Access - Can be accessed from anywhere

Lazy Loading - Created only when needed (in some implementations)

Disadvantages

Hard to Test - Difficult to mock in unit tests

Global State - Can make code harder to understand

Threading Issues - Need to handle multiple threads carefully

When to Use Singleton

Good for:

  • Database connections
  • File/Network managers
  • Logging systems
  • Configuration settings
  • Cache managers

Avoid for:

  • Regular business objects
  • When you need multiple instances later
  • When testing is important

Key Takeaways

  1. Singleton ensures only one instance of a class
  2. Make the constructor private
  3. Provide a public static method to get the instance
  4. For beginners, use Eager Initialization
  5. For advanced users, Enum Singleton is the best

Final Tip

Don't overuse Singleton! It's often called an "anti-pattern" because it can make your code harder to test and maintain. Use it only when you truly need exactly one instance of something.

Remember: One remote, one TV. One singleton, one purpose!

Happy coding! ????