In this module, you learned about the Singleton design pattern. The Singleton pattern is a creational pattern that lets you create a single instance of the class and provides and controls access to it through a public static method. A nonpublic constructor prevents clients from creating new instances of the class.
The Singleton pattern is used to ensure that only one object of a particular class is instantiated.
The Singleton pattern is used for single-threaded applications.
Review the Primary Elements that make up the Singleton Pattern in Software Development
The Singleton Pattern is a creational design pattern that ensures a class has only one instance while providing a global point of access to it. This is particularly useful when exactly one object is needed to coordinate actions across a system.
Here are the "primary elements" that make up the Singleton Pattern:
Private Constructor
The constructor is declared private to restrict instantiation of the class from outside.
This ensures that the class cannot be instantiated using the new keyword from other classes.
public class Singleton {
private Singleton() {
// Private constructor
}
}
Static Instance Variable
A static variable holds the single instance of the class.
This is the core of the pattern, as it stores the instance that will be shared across all requests for it.
Eager Initialization: The instance is created at the time of class loading.
Lazy Initialization: The instance is created only when it is first accessed.
private static Singleton instance;
Public Static Access Method
A public static method provides a global point of access to the instance.
It returns the same instance every time it is called, ensuring that only one instance exists.
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
Thread Safety (Optional)
In multithreaded environments, thread safety must be ensured to prevent multiple threads from creating separate instances.
Solutions include:
Using the synchronized keyword for the access method.
Implementing double-checked locking.
Leveraging the Initialization-on-Demand Holder idiom in Java.
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Global Access Point
The Singleton pattern ensures there is a global and consistent way to access the instance.
Typically, the static getInstance() method acts as this access point.
Optional Enhancements
Serialization Safe Singleton:
To prevent a new instance from being created during deserialization, implement the readResolve method.
Override the clone method to prevent the Singleton instance from being cloned.
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Cannot clone a Singleton object");
}
Enum Singleton:
Using an enum in Java is a simple way to implement a Singleton, as enums are inherently thread-safe and prevent serialization issues.
public enum Singleton {
INSTANCE;
}
Example Overview
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Key Principles
Single Instance: Ensure only one instance of the class exists.
Controlled Access: Provide a single access point to the instance.
Prevent Instantiation: Prevent external instantiation via private constructors.
Thread Safety: Ensure thread safety when multiple threads might access the instance.
These elements ensure the Singleton Pattern fulfills its purpose efficiently and reliably.
Motivation for the Singleton
Sometimes it's important to have only one instance for a class. For example, in a system there should be only one window manager or only one print spooler.
Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.
The singleton pattern involves only one class which is required to instantiate itself and to make sure it creates not more than one instance.
At the same time it provides a global point of access to that instance. In this case the same instance can be accessed from anywhere, making it impossible to directly invoke the constructor each time.
Intent
Ensure that only one instance of a class is created.
Provide a global point of access to the object.
Implementation
The implementation involves
a static member in the "Singleton" class,
a private constructor and
a static public method that returns a reference to the static member.
The Singleton Pattern defines a getInstance operation which exposes the unique instance which is accessed by the clients.
getInstance() is is responsible for creating its class unique instance in case it is not created yet and to return that instance.
The upcoming modules introduce you to many more patterns.
In the next module, you will have a chance to work with another creational pattern, the "factory method" pattern.