Basics of Design Patterns — Singleton 👑

Martin Jurran
Software Design Patterns
5 min readJul 17, 2024

Singleton allows you to create a class that only has one instance, while offering a single, global access point to said instance.

Real-World Analogy 🌍

The Singleton pattern is kind of like what you might see in a mirror maze. You see lots of copies of a person, but there is really only one actual person. You can interact with the copies without any issues, but you can’t tell which one is real (unless you get up close and examine the mirror).

Problem 🤔

Clients might not realize they’re interacting with the same instance of the object constantly

The Singleton solves two common software development problems, while violating the Single Responsibility Principle:

  1. Making sure a class can only have one instance. For shared resources such as databases, caches, or files, it’s best to have only one instance of their class to manage access.
  2. Provide a single point of access to one instance. Previously, global variables were utilized to store objects for universal use, causing safety issues as the value could be overwritten from any part of the code and harm the application. A safer approach is to use a singleton which performs similar to a global variable allowing access to the same object from any part of the program, however it is also safeguarded from being overwritten by other code.

Solution 💡

To create a singleton, it takes two common steps:

  1. Make the constructor private, preventing objects from using the new operator with said class.
  2. Create a static field holding the class value, serving as a cache.
  3. Create a static initialization method that either (1) calls the private constructor of said object or (2) returns the object from the static field

Structure 🏗️

  1. Private Constructor
  2. Static field caching the object itself
  3. Static initialization method, constructors object from (1) private constructor and returns the same instance of it’s own class from (2) static field.

public class Singleton {
private static Singleton instance = null;

private Singleton() {
// Private constructor to prevent instantiation by external clients
}

public static Singleton getInstance() {
if (instance == null)
instance = new Singleton();

return instance;
}
}

Pros and Cons

Pros

You can ensure that a specific class always has one and only one instance. This is especially useful when you want to control the creation and accessibility of an object in your program, such as a configuration manager or a cache.

You gain a single global access point to that instance. This access point can easily be reused throughout your code.

The object is only initialized when it’s requested for the first time. In other words, the object isn’t created until it’s actually needed, which can help save memory and resources.

Cons

Violates Single Responsibility Principle, as it often serves two purposes at once. In addition to (1) providing access to a single instance of a class, the Singleton also serves (2) as a global point of access throughout an application.

Hides bad software design. Might cause situations where parts of the program are tightly-coupled with each other.

Issues with multithreading. This pattern needs special treatment in multithreaded environments, to avoid each thread created a new instance.

Issues with unit testing. As they cannot be easily mocked in most test frameworks due to their private constructors. This can make it difficult or impossible to test code that depends on the Singleton.

Global state —making it difficult to reason about the system’s behavior and causing hard-to-debug bugs. Changes to the Singleton object can have unintended side effects, and understanding the relationship between different parts of the system can be challenging due to the global state.

❌ Performance issues — in heavily-used systems, the singleton pattern can introduce performance issues, as access to the singleton must be synchronized to prevent concurrent access. This can lead to reduced performance.

❌ Difficult to refactor — once a Singleton has been used extensively throughout code, it can be difficult to refactor code to remove the singleton. This is because access to the singleton may be spread throughout the code, making it difficult to identify all the dependencies.

Relation with other patterns

  • A Facade pattern can often be transformed into a Singleton since, in most cases, only one facade object is required.
  • The Flyweight pattern would resemble a Singleton if all the shared states of the objects were reduced to just one flyweight object.
  • Abstract Factory, Builder, and Prototype patterns can be implemented as Singletons.
  • Factory Method can be implemented to create Singletons.

Glossary

Instance

Instance — An object that is created from a class or blueprint, which contains its own unique set of data and methods to perform actions on that data. (Source: Techopedia, https://www.techopedia.com/definition/3750/instance)

Refactoring

Refactor — The process of restructuring existing code, without changing its external behavior, to improve readability, maintainability, and/or performance. (Source: Martin Fowler, https://martinfowler.com/books/refactoring.html)

Global State

A global state is a set of local states which occur simultaneously. (Source: Principles of Distributed Systems, Global State | SpringerLink)

Mocking

Mocking — The process of creating fake objects or functions to simulate the behavior of real objects or functions, in order to test the code that depends on them. Mocking is often used to isolate the code being tested from other parts of the system, and enables testing to occur in isolation from external dependencies. (Source: Martin Fowler, https://martinfowler.com/articles/mocksArentStubs.html)

About this series

I noticed personally, that design patterns still remain a mistery to a lot of software engineers, even though these concepts are nothing new and have been around for decades.

I want to solve this problem with this article series to help other software engineers grow.

Feel free to comment in case you find mistakes or want to add your own perspective!

(Photo by the author, Illustrations by Takashi Mifune under free use)

--

--

Martin Jurran
Software Design Patterns

Personal blog of a Software Engineer | Azure DevOps, C#/.NET, JavaScript