Singleton: Structure Diagrams
This course uses rectangles for classes and rounded rectangles for objects.
Connections between pointers and the objects they point to are indicated by arrows.
As much information about a class's methods and fields as is important is provided.
Singleton Design Pattern
In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object.
This is useful when exactly one object is needed to coordinate actions across the system.
Sometimes it is generalized to systems that operate more efficiently when only one or a few objects exist. It is also considered an anti-pattern since it is often used as a euphemism for global variable. In C++ it also serves to isolate from the unpredictability of the order of dynamic initialization, returning control to the programmer.
Singleton Implementation
Implementation of a
Singleton Pattern must satisfy the single instance and global access principles.
The Singleton requires a mechanism to access the singleton class member without creating a class object and a mechanism to persist the value of class members among class objects. The
Singleton Pattern is implemented by creating a class with a method that creates a new instance of the class if one does not exist. If an instance already exists, it simply returns a reference to that object. To make sure that the object cannot be instantiated any other way, the constructor is made private. Note the distinction between
- a simple static instance of a class and
- a singleton.
Although a singleton can be implemented as a static instance, it can also be constructed, requiring no memory or resources until needed. Another notable difference is that static member classes cannot implement an interface, unless that interface is simply a marker. So if the class has to realize a contract expressed by an interface, it really has to be a singleton. The singleton pattern must be carefully constructed in multi-threaded applications.
If two threads are to execute the creation method at the same time and a singleton does not yet exist, they both must check for an instance of the singleton and then only one should create the new one. If the programming language has concurrent processing capabilities the method should be constructed to execute as a mutually exclusive operation.
The classic solution to this problem is to use mutual exclusion on the class that indicates that the object is being instantiated.
Implementing Singleton Design Pattern with Constructor-Based Initialization in Java
In the realm of design patterns, the Singleton pattern ensures that a class has only one instance and provides a global point to access it. Traditionally, Singleton instances are created using a static instance variable. However, it is also possible to construct the Singleton instance using a constructor, particularly when parameterized construction is required or when leveraging dependency injection frameworks.
Below is an authoritative Java example that demonstrates how to implement a Singleton class where the Singleton instance is constructed using a constructor.
The Singleton Class with Constructor-Based Initialization
public class Singleton {
private static Singleton instance;
private final String parameter;
private Singleton(String parameter) {
this.parameter = parameter;
}
public static synchronized Singleton getInstance(String parameter) {
if (instance == null) {
instance = new Singleton(parameter);
}
return instance;
}
public String getParameter() {
return this.parameter;
}
}
Usage Example
public class Main {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance("Parameter1");
Singleton instance2 = Singleton.getInstance("Parameter2");
// Confirming that both instances are the same
System.out.println("Instance 1 hash: " + instance1.hashCode());
System.out.println("Instance 2 hash: " + instance2.hashCode());
// Confirming that the parameter remains consistent
System.out.println("Instance 1 parameter: " + instance1.getParameter());
System.out.println("Instance 2 parameter: " + instance2.getParameter());
}
}
Discussion
- Parameterized Constructor: The `Singleton` class has a private constructor that accepts a parameter. This allows for the Singleton instance to be initialized with specific settings or configurations.
- Synchronized `getInstance` Method: The `getInstance()` method is synchronized to ensure thread safety. This guarantees that only one instance of the Singleton class is created, even in a multi-threaded environment.
- Lazy Initialization: The Singleton instance is created only when the `getInstance()` method is first called. This is known as lazy initialization and is particularly useful for resource-intensive objects.
- Immutable Parameter: Once the Singleton instance is created, the parameter passed to the constructor remains immutable. Any subsequent calls to `getInstance()` with a different parameter will still return the original instance.
- Global Access Point: The `getInstance()` method serves as a global access point to the Singleton instance, ensuring that every part of the application uses the same instance.
By adhering to these principles and design considerations, you can implement a robust Singleton class in Java where the Singleton instance is constructed using a constructor. This approach is especially useful when you need to initialize the Singleton instance with specific parameters or when integrating with dependency injection frameworks.