Singleton Design Pattern

Learn via video courses
Topics Covered

Overview

Singleton design pattern is a creational design pattern that makes sure that a class has only one instance and is globally accessible by all other classes. Singleton design pattern reduces memory usage by sharing a single instance across the application.

When Will We Need Singleton Pattern?

Consider we want to create a LoggerService class which we can use across our project to log. Almost all the classes will use the LoggerService to log info, warn, error, etc. If every class creates a new LoggerService instance, it will occupy more memory, leading to an out-of-memory error. Singleton pattern, in this case, ensures that only one instance of this class is created and accessible globally throughout the project context.

introduction to Singleton Design Pattern

Singleton pattern might be useful if the three conditions are met. However, these might not be exhaustive with complex use cases and applications.

  • You need to control concurrent access to a shared resource.
  • Only one instance of the object is sufficient throughout the context of the application.
  • More than one independent parts of the application require access to the resource.

How Does Singleton Design Pattern Work?

We take the LoggerService example and implement in with the singleton design pattern. We write the LoggerService as a singleton and restrict other classes to instansiate it. The LoggerService class will have a single instance, and it will be available globally across our application.

Structure

Singleton design pattern has two core participants: Singleton and Client.

working of Singleton Design Pattern

Singleton
Singleton is a class with only one instance, and it is globally accessible by other classes across our application. E.g., LoggerService.

How to make a class Singleton?

  • It should have a private constructor so that no instance of it can be created by other classes.
  • It should have a public static method so that the it can be called (SingletonClass.getInstance()) to get its singleton instance

Client
The client interacts with the singleton class to get its shared instance and use it to call its methods. E.g., the log() method of the LoggerService singleton is used for logging messages.

Implementation

  1. Create the singleton class LoggerService with a private constructor and a public static method to get the instance.
  2. Add a public log() method to the LoggerService class used to log messages.
  3. Create the client class Client that uses the LoggerService singleton instance to log messages.

Achieving 100% Singletons

Static variables are initialized at the compile time. This means we will have singleton instances even if they are not needed during the run time.

Lazy Initialisation

One way to solve this problem is by using lazy initialization. Using this method, the instance is created when the singleton object is accessed for the first time. We declare the getLogger() method as synchronized so multiple threads cannot access the method simultaneously.

Using Enums

Enums are often categorized as one of the better ways to achieve Singletons. In some cases, the earlier discussed methods (defined using private variables) lack 100% achievability.

We have a public class named LoggerService, and we used a private constructor to create a singleton. But note that there are more than one ways to create an object. In Java, objects can also be created using other techniques like Reflection and Serialisation / Deserialisation. Both these methods will create new instances of the class even if the constructor in the class is private.

If we happen to use ENUMs, we might be able to solve this problem.

Enum is a special type of class and the above LoggerEnum will be compiled like below. The first time when the LOGGER is accessed, the LoggerEnum instance will be loaded and initialized.

Pseudocode

pseudocode of Singleton Design Pattern

LoggerService

Singleton class has only one instance and is shared across the application.

Client

Client class that uses the singleton instance to log messages.

Output

Explanation

We create the LoggerService class as singleton that has only one instance. We used the shared instances in our main() method to log the message.

Language Specific Code

Java

LoggerService

Client

Output

C++

LoggerService

Output

Client

Output

Python

LoggerService

Client

Output

Pros and Cons of Singleton Design Pattern

Pros

  • Singleton design pattern guarantees that only one instance of the class will be available throughout the application context. This ensures that you do not waste memory for a new object instance when you don’t need one.
  • Singleton design pattern might be handy when dealing with concurrent access to resources. Singletons can also provide thready safety.
  • Singleton design pattern eliminates the unnecessary instantiation overhead, i.e., the extra memory required to create an object.

Cons

  • Singleton design pattern introduces a global state in the application. This makes unit testing difficult. The global state does not align well with unit testing because it increases coupling, and control over more than one unit is needed while writing the unit tests.
  • Due to the resource being locked in a parallel processing environment, multi-threading in some cases can not be used to its full potential with singelton design pattern.
  • Singleton design pattern solves less than it causes. This means this pattern has minimal practical use cases and, if used otherwise, can generate more problems. Some of these are also direct violations of other design patterns. (e.g., Single Responsibility)

Difference between Singleton Pattern vs Flyweight Pattern

Singleton Design PatternFlyweight Design Pattern
Singleton design pattern provides a single instance of a class for the entire applicationFlyweight design pattern provides shared instance that can have overridden states
Singleton design pattern has only intrinsic states (cannot be modified)Flyweight design pattern has both intrinsic and extrinsic states (can be modified)
Example: LoggerService class has only one instance and is shared across applicationsExample: A Car class can have shared attributes (intrinsic) such as color and unshared attributes like registration number (extrinsic)

Forge your path as an Instagram System Design specialist through our course, a blueprint for becoming a design luminary.

FAQs

Q: When should I use singleton design pattern?

A: Singelton design pattern has limited practical use cases. To best judge, if you need to use the Singleton pattern, you should consider the three points mentioned above.

  • You need to control concurrent access to a shared resource.
  • Only one instance of the object is sufficient throughout the application's context.
  • More than one independent application part requires access to the resource.

Q: Are there other ways to achieve singleton without using private constructors?

A: Having a private constructor is to restrict the external world to instantiate the Singleton class. If we can achieve the same by other means, we can achieve Singleton without using private constructors. One of the ways is to use enums.