CHAPTER 06
Intermediate
Singleton Pattern
Updated: May 16, 2026
25 min read
# CHAPTER 6
Singleton Pattern
1. Introduction
Imagine you are building a web application that connects to a database. If 10 different classes need to query the database, and every class callsnew DatabaseConnection(), you have just opened 10 separate network connections to your database server. If 1,000 users do this, you open 10,000 connections, and your database crashes instantly. You need a way to ensure that *exactly one* connection object is created, and every class in your application shares that exact same instance. This is the exact problem solved by the Singleton Pattern. In this chapter, we will master the Singleton. We will learn how to lock down object creation, implement Lazy Initialization, and explore the dangerous architectural trade-offs of global state.
2. Learning Objectives
By the end of this chapter, you will be able to:- Define the intent and structure of the Singleton Pattern.
- Implement a basic Singleton using a private constructor and a static method.
- Understand the concept of "Lazy Initialization."
- Analyze the thread-safety issues of Singletons in multi-threaded environments.
- Discuss why the Singleton is often considered an "Anti-Pattern" in modern testing.
3. The Singleton Concept
The Singleton pattern has two strict requirements:-
1.
Ensure a class has only one instance. (Stop people from using
new).
- 2. Provide a global point of access to that instance. (Let anyone use it easily).
4. Implementation Steps
How do we stop developers from usingnew?
-
1.
Make the Constructor Private: If
__construct()is private, nobody outside the class can instantiate it.
- 2. Create a Static Property: Create a private static variable inside the class to hold the single instance.
-
3.
Create a Static Getter: Create a public static method (usually called
getInstance()). This method checks if the static property is empty. If it is, it creates the object (from *inside* the class) and saves it. If it is not empty, it simply returns the saved object.
5. Lazy Initialization
Notice the logic above: the object is only created *the very first time* someone callsgetInstance(). If the application runs but nobody ever needs the database, the connection is never created, saving memory. This is called Lazy Initialization.
6. UML Diagram
*Singleton Class Structure*
text
7. Code Example (PHP)
Here is the classic implementation of a Database Logger using a Singleton in PHP.
php
8. Best Practices (Thread Safety)
If you are writing in a multi-threaded language like Java or C#, the basic Singleton is dangerous. If two threads callgetInstance() at the exact same millisecond, they might both see instance == null, and both will create a new object, violating the Singleton rule.
*Best Practice:* You must use "Locks" (e.g., synchronized in Java) inside the getInstance() method to ensure only one thread can create the object at a time.
9. Common Mistakes (The Anti-Pattern Debate)
Many senior architects consider the Singleton an Anti-Pattern. Why?-
Global State: Singletons are essentially glorified global variables. They hide dependencies. If a
Checkoutclass secretly callsLogger::getInstance()deep inside its code, you can't easily see that dependency from the outside.
- Testing Nightmare: Unit testing a Singleton is incredibly difficult. Because the state is global, if Test A modifies the database Singleton, Test B might fail because it is using the exact same mutated instance.
- *The Modern Alternative:* Dependency Injection (DI) containers. Modern frameworks (Laravel, Spring) create a single object and *inject* it where needed, achieving the same goal without the global state issues.
10. Mini Project: Build a Configuration Manager
-
1.
Create a
ConfigManagerSingleton class.
-
2.
In its private constructor, load an array of fake settings (e.g.,
['theme' => 'dark', 'lang' => 'en']).
-
3.
Add a
getSetting($key)method.
-
4.
From three different random functions in your script, call
ConfigManager::getInstance()->getSetting('theme')to prove they all share the same configuration memory.
11. Practice Exercises
-
1.
Explain exactly how making a constructor
privatephysically enforces the first rule of the Singleton pattern.
- 2. Define "Lazy Initialization." Why is it highly beneficial for heavy objects like Database Connections?
12. MCQs with Answers
Question 1
In the standard Singleton design pattern implementation, how is the global access method (usually named getInstance()) defined?
Question 2
Why is the Singleton pattern frequently criticized as an "Anti-Pattern" by modern software architects who focus heavily on Unit Testing?
13. Interview Questions
- Q: Write a thread-safe Singleton pattern in your preferred programming language on the whiteboard. Explain how you prevent a race condition during initialization.
-
Q: A junior developer uses the
clonekeyword to duplicate your Singleton object, successfully bypassing the private constructor. How do you defensively program your Singleton class to prevent cloning?
- Q: Compare the Singleton pattern to simply defining a massive global variable file. What structural advantages does the Singleton offer?
14. FAQs
Q: Can I pass arguments togetInstance($config)?
A: You can, but it is a bad idea. If Thread A calls getInstance('mysql') and creates the object, and later Thread B calls getInstance('postgres'), Thread B will just receive the already-created MySQL instance. This causes massive logical bugs. Singletons should generally be parameterless.