The Singleton Design Pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to it. It is commonly used to control access to shared resources, such as a database connection, configuration settings, or logging mechanisms.
Key Characteristics of Singleton
- Single Instance: Ensures that only one instance of the class exists throughout the application.
- Global Access Point: Provides a single point of access to the instance.
- Lazy Initialization: The instance is created only when it is first accessed, saving resources.
Steps to Implement a Singleton
- Private Constructor: Prevents other classes from instantiating the class directly.
- Private Static Variable: Holds the single instance of the class.
- Public Static Method: Provides a global access point to the instance.
Implementation in Java
public class Singleton {
// Step 1: Create a private static variable for the single instance.
private static Singleton instance;
// Step 2: Make the constructor private to prevent instantiation.
private Singleton() {}
// Step 3: Provide a public static method to access the instance.
public static Singleton getInstance() {
if (instance == null) {
// Lazy initialization: Create the instance only when needed.
instance = new Singleton();
}
return instance;
}
// Additional methods of the class
public void showMessage() {
System.out.println("Singleton Instance Accessed!");
}
}
Usage Example
public class Main {
public static void main(String[] args) {
// Access the Singleton instance
Singleton singleton = Singleton.getInstance();
// Use the Singleton instance
singleton.showMessage();
}
}
Thread-Safe Singleton (Java)
In multi-threaded environments, ensure the Singleton is thread-safe:
public class ThreadSafeSingleton {
private static ThreadSafeSingleton instance;
private ThreadSafeSingleton() {}
public static synchronized ThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}
Alternatively, use the Bill Pugh Singleton Design with a static inner class for better performance:
public class BillPughSingleton {
private BillPughSingleton() {}
private static class SingletonHelper {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
Advantages
- Controlled Instance Creation: Only one instance is created and reused.
- Global Access: Simplifies access to a shared resource.
- Lazy Initialization: Saves memory and resources.
Disadvantages
- Global State: Can make unit testing difficult as the state persists across tests.
- Concurrency Issues: Requires proper handling in multi-threaded environments.
- Tight Coupling: Increases dependency on the Singleton class.
Use Cases
- Database Connections: Ensures only one connection pool is created.
- Logging: Centralizes logging across an application.
- Configuration: Stores application-wide configuration settings.
- Caching: Manages a single instance of cache storage.
The Singleton pattern is widely used but should be applied carefully to avoid anti-patterns like unnecessary global states.