Singleton Pattern

The Singleton pattern is a design pattern that ensures a class has only one instance and provides a global point of access to it. It’s commonly used when you need exactly one object to coordinate actions across a system, like a configuration manager or a database connection pool.

Important Features

  • Single Instance: Restricts instantiation to one object.
  • Global Access: Provides a single point (e.g., a static method) to access the instance.
  • Lazy Initialization (optional): Creates the instance only when first requested.

Structure of Singleton Pattern

The structure typically involves:

  • A static member variable that holds the single instance of the class.
  • A private constructor to prevent instantiation from other classes.
  • A static method to provide access to the single instance.
public class Singleton {
    // Private static instance
    private static Singleton instance = null;
    
    // Private constructor to prevent instantiation
    private Singleton() {
        // Prevent reflection-based instantiation
        if (instance != null) {
            throw new RuntimeException("Use getInstance() to get the singleton instance.");
        }
    }
    
    // Public static method to access the instance
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}Code language: PHP (php)

Use case and Implementation

Managing a single instance of the `BankManager` class to handle global configuration and resources like database connections.

//SingletonPatternDemo.java
class BankManager {
    // Private static instance variable
    private static BankManager instance = null;
    // Private constructor to prevent instantiation outside the class
    private BankManager() {
        // Initialize resources like database connections here
        System.out.println("BankManager instance created. Initializing resources...");
        // Simulating resource initialization (e.g., database connection)
        // This could involve more complex initialization code
        // For demonstration, just printing a message
        System.out.println("Resources initialized.");
    }
    // Public static method to get the singleton instance
    public static BankManager getInstance() {
        // Lazy initialization: create instance if null
        if (instance == null) {
            instance = new BankManager();
        }
        return instance;
    }
   // Example method to simulate using the singleton instance
    public void performBankOperation(String operation) {
        // Simulate performing a bank operation using resources
        System.out.println("Performing bank operation: " + operation);
        // Example: Database operation or any resource operation
    }
   // Example cleanup method (not always necessary)
    public void cleanupResources() {
        // Clean up resources here if needed
        System.out.println("Cleaning up resources...");
    }
    // Example method to demonstrate the singleton's functionality
    public void printManagerDetails() {
        System.out.println("BankManager instance details: " + this);
    }
}
// Main class to demonstrate the usage of the Singleton pattern
public class SingletonPatternDemo {
    public static void main(String[] args) {
        // Get the singleton instance of BankManager
        BankManager manager1 = BankManager.getInstance();
        manager1.printManagerDetails();
        // Perform operations using the singleton instance
        manager1.performBankOperation("Deposit");
        manager1.performBankOperation("Withdrawal");
       // Demonstrate that it is the same instance
        BankManager manager2 = BankManager.getInstance();
        manager2.printManagerDetails();
       // Both manager1 and manager2 should refer to the same instance
        if (manager1 == manager2) {
            System.out.println("manager1 and manager2 are the same instance.");
        }
       // Clean up resources if needed (not always necessary)
        manager1.cleanupResources();
    }
}
/*
D:\>javac SingletonPatternExample.java

D:\>java SingletonPatternExample
BankManager instance created. Initializing resources...
Resources initialized.
BankManager instance details: BankManager@4a574795
Performing bank operation: Deposit
Performing bank operation: Withdrawal
BankManager instance details: BankManager@4a574795
manager1 and manager2 are the same instance.
Cleaning up resources...
*/

When you run SingletonPatternDemo, it will demonstrate that both manager1 and manager2 are indeed the same instance of BankManager, confirming the Singleton pattern’s implementation.This demo shows how the Singleton pattern can be used to ensure there is only one instance of BankManager managing global configuration and resources like database connections throughout the application.

Pros

  • Controlled access to a single instance.
  • Reduces memory usage by avoiding multiple instances.
  • Useful for shared resources like loggers or caches.

Cons

  • Can introduce global state, making code harder to test and maintain.
  • Not inherently thread-safe unless explicitly implemented.
  • Difficult to subclass or mock in unit tests.

When to Use

  • Managing shared resources (e.g., database connections, thread pools).
  • Centralized management of configuration settings.
  • Logging or monitoring systems.

The Singleton Pattern is a powerful creational design pattern that ensures a class has only one instance while providing a global point of access to it. In Java, it’s especially useful for managing shared resources like database connections, logging, configuration settings, and application-level caches. By restricting instantiation and controlling access through a static method, Singleton promotes controlled resource usage and centralized management.

Scroll to Top