Singleton design Pattern in java with example and possible way to create Singleton Pattern
The Singleton Design Pattern ensures that a class has only one instance and provides a global point of access to that instance. It is often used when exactly one object is needed to coordinate actions across the system. Here’s an example of a Singleton Pattern in Java and then we’ll discuss possible ways to implement it:
Singleton design pattern example
Example# 1:
/*
* Author: Zameer Ali Mohil
* */
public class Singleton {
// Private static instance variable
private static Singleton instance;
// Private constructor to prevent instantiation from outside the class
private Singleton() {
// Initialization code, if any
}
// Public method to provide the global point of access to the instance
public static Singleton getInstance() {
// Lazy initialization: create the instance only if it doesn't exist
if (instance == null) {
instance = new Singleton();
}
return instance;
}
// Other methods and properties of the singleton class
public void showMessage() {
System.out.println("Hello, I am a Singleton!");
}
}
public class SingletonPatternExample {
public static void main(String[] args) {
// Get the singleton instance
Singleton singleton = Singleton.getInstance();
// Use the singleton instance
singleton.showMessage();
}
}
In this example:
- The
Singleton
class has a private static instance variable and a private constructor. - The
getInstance()
method provides the global point of access to the singleton instance. - The
getInstance()
method uses lazy initialization, creating the instance only if it doesn’t exist. - The
main
method inSingletonPatternExample
demonstrates how to get the singleton instance and use it.
Example# 2:
Let’s consider a practical example where a Configuration
class is implemented as a singleton. This class is responsible for storing configuration settings for an application, and having only one instance ensures that all parts of the application use the same configuration.
/*
* Author: Zameer Ali Mohil
* */
public class Configuration {
// Private static instance variable
private static Configuration instance;
// Configuration settings (example: database URL, API keys, etc.)
private String databaseUrl;
private String apiKey;
// Private constructor to prevent instantiation from outside the class
private Configuration() {
// Default configuration settings
this.databaseUrl = "jdbc:mysql://localhost:3306/mydatabase";
this.apiKey = "your-api-key";
}
// Public method to provide the global point of access to the instance
public static Configuration getInstance() {
// Lazy initialization: create the instance only if it doesn't exist
if (instance == null) {
instance = new Configuration();
}
return instance;
}
// Getter and setter methods for configuration settings
public String getDatabaseUrl() {
return databaseUrl;
}
public void setDatabaseUrl(String databaseUrl) {
this.databaseUrl = databaseUrl;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}
public class SingletonPatternExample {
public static void main(String[] args) {
// Get the singleton instance of Configuration
Configuration config = Configuration.getInstance();
// Use the singleton instance to get and set configuration settings
System.out.println("Database URL: " + config.getDatabaseUrl());
System.out.println("API Key: " + config.getApiKey());
// Modify the configuration settings
config.setDatabaseUrl("jdbc:mysql://newhost:3306/newdatabase");
config.setApiKey("new-api-key");
// Access the modified settings through the same instance
System.out.println("Modified Database URL: " + config.getDatabaseUrl());
System.out.println("Modified API Key: " + config.getApiKey());
}
}
In this example:
- The
Configuration
class is a singleton that stores configuration settings. - The
getInstance()
method is used to get the singleton instance ofConfiguration
. - The configuration settings can be accessed and modified using getter and setter methods.
- The
SingletonPatternExample
class demonstrates how to use the singleton instance to access and modify configuration settings.
This example illustrates how the Singleton Pattern ensures that there is only one instance of the Configuration
class throughout the application, allowing consistent access to configuration settings from different parts of the code.
Possible Ways to Implement Singleton Pattern:
1. Lazy Initialization: This is the most common way to implement a singleton. The instance is created only if it is needed for the first time.
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
2. Eager Initialization: In this approach, the instance is created when the class is loaded, whether it is needed or not. It ensures thread safety at the cost of early initialization.
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
3. Thread-Safe Singleton (Double-Checked Locking): This approach ensures thread safety in a multithreaded environment. It uses double-checked locking to reduce the overhead of acquiring a lock every time.
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
4. Bill Pugh Singleton Design: This is a modern way to implement the singleton pattern using a static inner helper class. It provides lazy initialization and thread safety without the need for synchronization.
public class Singleton {
private Singleton() {
// Initialization code, if any
}
private static class SingletonHelper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
5. Enum Singleton: Enums provide a concise way to create a singleton in Java. Enums are inherently serializable and thread-safe.
public enum Singleton {
INSTANCE;
// Other methods and properties of the singleton
public void showMessage() {
System.out.println("Hello, I am an Enum Singleton!");
}
}
Choose the appropriate method based on your requirements. The lazy initialization approach is commonly used as it balances between resource utilization and thread safety. The enum singleton is also a recommended approach in modern Java for its simplicity and inherent thread safety.