Tutorial Playlist
The Singleton design pattern is a creational pattern that ensures that only one instance of a class is created throughout the entire runtime of an application. It provides a global point of access to this instance, allowing other objects to easily use it.
The Singleton pattern is useful in scenarios where having multiple instances of a class could lead to issues or unnecessary resource consumption. Some common examples include Database connection, logging and configuration settings.
The Singleton pattern is typically used in situations where you need to ensure that only one instance of a class is created and that it can be accessed globally. Here are some scenarios where the Singleton pattern is commonly employed:
1. Database Connections: To carry out various actions when working with a database, it is frequently essential to create a connection. Multiple database connections might use a lot of resources and result in problems like connection pool exhaustion.
2. Caching: In applications that involve caching data, a Singleton pattern can be used to manage the cache instance. A single cache instance can be shared by different parts of the application, ensuring that the data remains consistent and reducing redundancy.
3. Logger: For monitoring and debugging purposes, logging is a crucial component of any application. You can create a single logger object that can be accessed by several application components by using the Singleton design. Logs are aggregated and consistent as a result.
4. Configuration Settings: Global configuration settings are often required in applications, such as application-wide settings or environment variables. Implementing these settings as a Singleton allows easy access to the configuration values from anywhere in the codebase.
5. Thread Pools: In multithreaded applications, managing thread pools with the Singleton design might be advantageous. It enables the application's various components to share a pool of threads for task execution, ensuring effective resource utilization.
6. GUI Components: In programmes that use graphical user interfaces (GUIs), there are times when you just need to build a single instance of a specific component, like a prominent window or a dialogue box.
The Singleton pattern typically involves the following characteristics:
Here's an example of a Singleton implementation in Java:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Implementation:
The Singleton pattern can be applied in numerous ways. The prior example used lazy initialization, where the instance is only created on the first call to getInstance(). But it can be difficult to get a 100% Singleton because there are so many things to take into account, like thread safety and avoiding serialization or cloning.
Achieving 100% Singletons:
1. Eager Initialization: In this approach, the instance is created eagerly at the time of class loading. It guarantees that the instance is always available, but it may consume resources even if it's not needed immediately.
2. Thread-Safe Initialization: To ensure thread safety, you can synchronize the getInstance() method or use double-checked locking. However, synchronization can impact performance.
Lazy Initialization:
Lazy initialization means the instance is created only when it is needed. It can be implemented as shown in the previous example. However, this implementation is not thread-safe. To achieve thread safety, you can use synchronization or employ the double-checked locking technique.
Using Enums:
A more modern approach to implementing singletons is by using enums. Enum values are instantiated only once by the JVM, making them inherently singletons. Here's an example:
public enum Singleton {
INSTANCE;
// Singleton methods and attributes can be defined here
}
The classic implementation of the Singleton pattern involves lazy initialization of the instance. Here's an example:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
To ensure thread safety and prevent multiple instances from being created, you can make the getInstance() method synchronized. Here's an example:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
In the eager instantiation approach, the instance is created eagerly at the time of class loading, ensuring that it is always available. Here's an example:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
return instance;
}
}
The "Double Checked Locking" technique combines lazy initialization with synchronization to achieve both thread safety and performance. Here's an example:
public class Singleton {
private volatile 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;
}
}
The "Double Checked Locking" approach is considered the best practice for implementing the Singleton pattern as it provides both thread safety and efficient lazy initialization.
The Singleton pattern's early instantiation refers to the creation of the singleton instance during class loading. To put it another way, the instance is eagerly constructed before it is truly required. Here is a Java illustration:
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
return instance;
}
}
The singleton instance is only produced when it is requested for the first time under the lazy singleton approach. To put it another way, the instance is haphazardly generated when it is truly required. Here is a Java illustration:
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
In situations when the Singleton instance is produced via class-loading processes, the classloader is crucial to the Singleton pattern. Classes are loaded into memory, and instances of those classes are created by the class loader.
The Singleton instance is often created when the class loader loads the class. This guarantees that the instance will be accessible and available for the duration of the application. The class loader, which loads the class and controls its lifetime, ensures that just one instance of the Singleton class is produced.
The process of transforming an item into a byte stream, which may be saved in a file or sent over a network, is referred to as serialization. The opposite of recreating the object from the byte stream is deserialization.
Serialisation can have the following effects about the Singleton pattern:
One real-life example where the Singleton pattern can be applied is a logging system. A logging system is typically a centralized component that handles logging messages from various parts of an application. It's desirable to have a single instance of the logging system throughout the application to ensure consistent logging behavior and avoid creating multiple logging instances.
Here's a simplified example in Java:
public class Logger {
private static Logger instance;
private Logger() {
// Private constructor
}
public static synchronized Logger getInstance() {
if (instance == null) {
instance = new Logger();
}
return instance;
}
public void log(String message) {
// Logging implementation
System.out.println(message);
}
}
Here's a pseudocode representation of the Singleton pattern:
class Singleton
private static instance: Singleton
private constructor()
// Private constructor to prevent external instantiation
public static getInstance() : Singleton
if the instance is null
instance = new Singleton()
return instance
Below listed are some of the language specific codes:
1. Singleton Design Pattern JavaScript:
// Singleton using a closure and IIFE (Immediately Invoked Function Expression)
const Singleton = (function () {
let instance;
function createInstance() {
// Private variables and methods can be defined here
return {
// Public methods and attributes can be defined here
};
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// Usage
const singletonInstance1 = Singleton.getInstance();
const singletonInstance2 = Singleton.getInstance();
console.log(singletonInstance1 === singletonInstance2); // Output: true
2. Singleton Design Pattern Python:
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
# Initialization can be done here
return cls._instance
# Usage
singletonInstance1 = Singleton()
singletonInstance2 = Singleton()
print(singletonInstance1 is singletonInstance2) # Output: True
3. Singleton Design Pattern Java:
java
Copy code
public class Singleton {
private static Singleton instance;
private Singleton() {
// Private constructor
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Usage
Singleton singletonInstance1 = Singleton.getInstance();
Singleton singletonInstance2 = Singleton.getInstance();
System.out.println(singletonInstance1 == singletonInstance2); // Output: true
4. Singleton Design Pattern C#:
public class Singleton
{
private static Singleton instance;
private Singleton()
{
// Private constructor
}
public static Singleton get instance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
// Usage
Singleton singletonInstance1 = Singleton.GetInstance();
Singleton singletonInstance2 = Singleton.GetInstance();
Console.WriteLine(singletonInstance1 == singletonInstance2); // Output: True
5. Singleton Design Pattern C++:
class Singleton {
public:
static Singleton& get instance() {
static Singleton instance;
return instance;
}
// Other public methods and attributes can be defined here
private:
Singleton() {
// Private constructor
}
// Private copy constructor and assignment operator to prevent cloning
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
// Usage
Singleton& singletonInstance1 = Singleton::GetInstance();
Singleton& singletonInstance2 = Singleton::GetInstance();
cout << (&singletonInstance1 == &singletonInstance2) << endl; // Output: 1 (True)
6. Singleton Design Pattern PHP:
class Singleton {
private static $instance;
private function __construct() {
// Private constructor
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
// Usage
$singletonInstance1 = Singleton::getInstance();
$singletonInstance2 = Singleton::getInstance();
echo ($singletonInstance1 === $singletonInstance2) ? 'true' : 'false'; // Output: true
In all the examples above, the Singleton pattern ensures that only one instance of the class is created and shared throughout the application. The static method getInstance() is used to access the single instance of the class.
Below listed are the pros and cons of Singleton design pattern example:
Pros:
Cons:
Singleton Pattern:
Flyweight Pattern:
When you want to make sure that only one instance of a class is produced and sold abroad, the Singleton design is a useful plan design. It offers a practical way to manage the production of items, improve asset utilization, and maintain a trustworthy state throughout the application. When planning your applications and choosing the best plan designs for your unique needs, you can make more educated decisions if you are aware of the strengths and weaknesses of these instances.
1. Can we subclass a Singleton class?
Yes, just like other classes, Singleton classes can be subclassed. The subclass will not, however, completely adhere to the Singleton pattern because, if not carefully built; it may have numerous instances.
2. Is the Singleton pattern thread-safe?
The classic implementation of the Singleton pattern without any synchronization is not thread-safe. However, thread safety can be achieved by using synchronization, double-checked locking, or other thread-safe mechanisms.
3. Can we create multiple instances of a Singleton using reflection?
Yes, it is possible to create multiple instances of a Singleton using reflection. However, it requires explicit manipulation of the class's private constructor and is considered an edge case.
PAVAN VADAPALLI
Popular
Talk to our experts. We’re available 24/7.
Indian Nationals
1800 210 2020
Foreign Nationals
+918045604032
upGrad does not grant credit; credits are granted, accepted or transferred at the sole discretion of the relevant educational institution offering the diploma or degree. We advise you to enquire further regarding the suitability of this program for your academic, professional requirements and job prospects before enrolling. upGrad does not make any representations regarding the recognition or equivalence of the credits or credentials awarded, unless otherwise expressly stated. Success depends on individual qualifications, experience, and efforts in seeking employment.
upGrad does not grant credit; credits are granted, accepted or transferred at the sole discretion of the relevant educational institution offering the diploma or degree. We advise you to enquire further regarding the suitability of this program for your academic, professional requirements and job prospects before enr...