Singleton
Intent
Ensure a class has only one instance, and provide a global point of access to it.
Problem
Some classes should have exactly one instance — a database connection pool, a logger, or a configuration manager. You need to guarantee that no additional instances can be created and provide easy access to that single instance.
Real-World Analogy
Think of a country’s emergency phone number, like 911. There’s exactly one number, everyone knows it, and you can’t just create a second one. No matter who dials it or from where, they all reach the same system. It was established once and is globally accessible to everyone — that’s a Singleton.
When You Need It
- You need a single shared database connection pool that every part of your application uses, and creating multiple pools would waste resources or cause conflicts
- You’re building a logging service that writes to one file — multiple logger instances would corrupt the file with interleaved writes
- You need a configuration manager that loads settings once at startup and provides them everywhere, and reloading or duplicating it would cause inconsistencies
UML Class Diagram
classDiagram
class Singleton {
-instance$: Singleton
-Singleton()
+getInstance()$ Singleton
+operation()
}
Sequence Diagram
sequenceDiagram
participant Client
participant Singleton
Client->>Singleton: getInstance()
alt first call
Singleton->>Singleton: create instance
end
Singleton-->>Client: instance
Client->>Singleton: operation()
Participants
| Participant | Role |
|---|---|
| Singleton | Defines a static getInstance() method that returns the unique instance. The constructor is private to prevent external instantiation. |
How It Works
- The Singleton class hides its constructor (private or protected).
- A static method
getInstance()checks if an instance already exists. - If not, it creates one; if so, it returns the existing instance.
- All clients access the same instance through
getInstance().
Applicability
Use when:
- There must be exactly one instance of a class, accessible from a well-known access point
- The sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code
Don’t use when:
- You need multiple instances later — Singleton makes this change difficult
- It introduces hidden global state that makes testing harder
Singleton is often considered an anti-pattern in modern software design because it introduces global state and makes unit testing difficult. Consider dependency injection as an alternative.
Trade-offs
Pros:
- Guarantees exactly one instance exists, preventing resource duplication
- Provides a global access point that’s easy to use from anywhere
- Lazy initialization — the instance is created only when first needed
Cons:
- Introduces hidden global state that makes unit testing difficult (hard to mock or reset)
- Violates the Single Responsibility Principle — manages its own lifecycle and business logic
- Can mask poor design — often a sign that dependency injection should be used instead
Example Code
C#
public sealed class AppConfig
{
private static readonly Lazy<AppConfig> _instance =
new(() => new AppConfig());
private AppConfig()
{
ConnectionString = "Server=localhost;Database=app";
}
public static AppConfig Instance => _instance.Value;
public string ConnectionString { get; }
public void ShowConfig() =>
Console.WriteLine($"Config: {ConnectionString}");
}
// Usage: AppConfig.Instance.ShowConfig();
Delphi
type
TAppConfig = class
private
class var FInstance: TAppConfig;
FConnectionString: string;
constructor CreatePrivate;
public
class function GetInstance: TAppConfig;
procedure ShowConfig;
property ConnectionString: string read FConnectionString;
end;
constructor TAppConfig.CreatePrivate;
begin
inherited Create;
FConnectionString := 'Server=localhost;Database=app';
end;
class function TAppConfig.GetInstance: TAppConfig;
begin
if FInstance = nil then
FInstance := TAppConfig.CreatePrivate;
Result := FInstance;
end;
procedure TAppConfig.ShowConfig;
begin
WriteLn('Config: ' + FConnectionString);
end;
// Usage: TAppConfig.GetInstance.ShowConfig;
C++
#include <iostream>
#include <string>
#include <mutex>
class AppConfig {
std::string connectionString_;
AppConfig() : connectionString_("Server=localhost;Database=app") {}
public:
AppConfig(const AppConfig&) = delete;
AppConfig& operator=(const AppConfig&) = delete;
static AppConfig& getInstance() {
static AppConfig instance;
return instance;
}
void showConfig() const {
std::cout << "Config: " << connectionString_ << "\n";
}
};
// Usage: AppConfig::getInstance().showConfig();
Runnable Examples
| Language | Source |
|---|---|
| C# | Singleton.cs |
| C++ | singleton.cpp |
| Delphi | singleton.pas |
Related Patterns
- Abstract Factory — a concrete factory is often a singleton
- Builder — Builder can be combined with Singleton for one-time construction
- Prototype — an alternative to Singleton when you need derived variants