1. Home
  2. /
  3. Docs
  4. /
  5. Design Pattern
  6. /
  7. Creational
  8. /
  9. Singleton
  10. /
  11. Examples

Examples

This page provides practical implementation examples of the Singleton pattern across multiple programming languages. Each example demonstrates thread-safe implementation and follows language-specific best practices.

C# Implementation

C# offers multiple ways to implement Singleton. Here’s a thread-safe implementation using lazy initialization:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy = 
        new Lazy<Singleton>(() => new Singleton());
    
    public static Singleton Instance 
    { 
        get { return lazy.Value; } 
    }

    private Singleton()
    {
        // Initialize resources
        Console.WriteLine("Singleton instance created");
    }

    public void DoSomething()
    {
        Console.WriteLine("Singleton method called");
    }
}

// Usage
class Program
{
    static void Main()
    {
        // Both variables reference the same instance
        Singleton s1 = Singleton.Instance;
        Singleton s2 = Singleton.Instance;
        
        Console.WriteLine(Object.ReferenceEquals(s1, s2)); // Output: True
        
        s1.DoSomething();
    }
}

Key Points:

  • Uses Lazy<T> for thread-safe lazy initialization
  • The sealed keyword prevents inheritance
  • Private constructor prevents external instantiation
  • .NET Framework handles thread safety automatically

Node.js (JavaScript/TypeScript) Implementation

JavaScript implementation using ES6 classes and module pattern:

class Singleton {
    constructor() {
        if (Singleton.instance) {
            return Singleton.instance;
        }
        
        // Initialize properties
        this.timestamp = Date.now();
        console.log('Singleton instance created');
        
        Singleton.instance = this;
    }
    
    doSomething() {
        console.log(`Singleton method called at ${this.timestamp}`);
    }
    
    static getInstance() {
        if (!Singleton.instance) {
            Singleton.instance = new Singleton();
        }
        return Singleton.instance;
    }
}

// Freeze the instance to prevent modifications
Object.freeze(Singleton);

// Usage
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // Output: true
instance1.doSomething();

// Alternative: Using Module Pattern
const DatabaseConnection = (() => {
    let instance;
    
    function createInstance() {
        return {
            connect: () => console.log('Connected to database'),
            query: (sql) => console.log(`Executing: ${sql}`)
        };
    }
    
    return {
        getInstance: () => {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

// Usage of module pattern
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();
console.log(db1 === db2); // Output: true

Key Points:

  • JavaScript is single-threaded, so no explicit thread safety needed
  • Module pattern provides a cleaner alternative
  • ES6 modules are singletons by default when exported
  • Object.freeze() prevents modifications

Python Implementation

Python offers several approaches. Here’s a thread-safe implementation using metaclasses:

import threading

class SingletonMeta(type):
    """
    Thread-safe Singleton metaclass implementation
    """
    _instances = {}
    _lock = threading.Lock()
    
    def __call__(cls, *args, **kwargs):
        with cls._lock:
            if cls not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances[cls] = instance
        return cls._instances[cls]

class Singleton(metaclass=SingletonMeta):
    def __init__(self):
        self.value = None
        print("Singleton instance created")
    
    def do_something(self):
        print(f"Singleton method called with value: {self.value}")

# Usage
if __name__ == "__main__":
    # Both variables reference the same instance
    s1 = Singleton()
    s2 = Singleton()
    
    print(s1 is s2)  # Output: True
    
    s1.value = "Hello"
    print(s2.value)  # Output: Hello
    
    s1.do_something()

# Alternative: Using decorator
def singleton(class_):
    instances = {}
    def get_instance(*args, **kwargs):
        if class_ not in instances:
            instances[class_] = class_(*args, **kwargs)
        return instances[class_]
    return get_instance

@singleton
class DatabaseConnection:
    def __init__(self):
        self.connected = False
        print("Database connection initialized")
    
    def connect(self):
        self.connected = True
        print("Connected to database")

# Usage
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2)  # Output: True

Key Points:

  • Metaclass approach provides elegant Singleton implementation
  • Threading lock ensures thread safety
  • Decorator pattern offers a simpler alternative
  • Python’s module system makes modules singletons by default

Go Implementation

Go implementation using sync.Once for thread-safe initialization:

package main

import (
    "fmt"
    "sync"
)

type Singleton struct {
    value string
}

var instance *Singleton
var once sync.Once

// GetInstance returns the singleton instance
func GetInstance() *Singleton {
    once.Do(func() {
        fmt.Println("Creating singleton instance")
        instance = &Singleton{
            value: "singleton",
        }
    })
    return instance
}

func (s *Singleton) DoSomething() {
    fmt.Printf("Singleton method called with value: %s\n", s.value)
}

func main() {
    // Both variables reference the same instance
    s1 := GetInstance()
    s2 := GetInstance()
    
    fmt.Println(s1 == s2) // Output: true
    
    s1.value = "modified"
    fmt.Println(s2.value) // Output: modified
    
    s1.DoSomething()
}

// Alternative: Using init function for eager initialization
var eagerInstance = &Singleton{
    value: "eager singleton",
}

func GetEagerInstance() *Singleton {
    return eagerInstance
}

Key Points:

  • sync.Once guarantees the initialization code runs only once
  • Thread-safe without explicit locking
  • Package-level variables provide eager initialization alternative
  • Idiomatic Go approach using package structure

C++ Implementation

Modern C++11 and later provides thread-safe static local variable initialization:

#include <iostream>
#include <mutex>
#include <memory>

class Singleton {
private:
    static std::mutex mutex_;
    std::string value_;
    
    // Private constructor
    Singleton(const std::string value) : value_(value) {
        std::cout << "Singleton instance created\n";
    }
    
    // Delete copy constructor and assignment operator
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // Thread-safe in C++11 and later
    static Singleton& getInstance(const std::string& value = "default") {
        static Singleton instance(value);
        return instance;
    }
    
    void doSomething() const {
        std::cout << "Singleton method called with value: " 
                  << value_ << "\n";
    }
    
    std::string getValue() const {
        return value_;
    }
    
    void setValue(const std::string& value) {
        value_ = value;
    }
};

// Initialize static member
std::mutex Singleton::mutex_;

// Usage
int main() {
    // Both variables reference the same instance
    Singleton& s1 = Singleton::getInstance("First");
    Singleton& s2 = Singleton::getInstance("Second");
    
    std::cout << "Same instance? " 
              << (&s1 == &s2 ? "Yes" : "No") << "\n";
    
    s1.setValue("modified");
    std::cout << "s2 value: " << s2.getValue() << "\n";
    
    s1.doSomething();
    
    return 0;
}

// Alternative: Using smart pointers for more complex scenarios
class ModernSingleton {
private:
    static std::unique_ptr<ModernSingleton> instance_;
    static std::once_flag initFlag_;
    
    ModernSingleton() {
        std::cout << "ModernSingleton instance created\n";
    }

public:
    static ModernSingleton& getInstance() {
        std::call_once(initFlag_, []() {
            instance_.reset(new ModernSingleton());
        });
        return *instance_;
    }
    
    ModernSingleton(const ModernSingleton&) = delete;
    ModernSingleton& operator=(const ModernSingleton&) = delete;
};

std::unique_ptr<ModernSingleton> ModernSingleton::instance_;
std::once_flag ModernSingleton::initFlag_;

Key Points:

  • C++11 guarantees thread-safe static local variable initialization
  • Delete copy constructor and assignment operator to prevent copies
  • std::call_once provides explicit thread-safe initialization
  • Modern C++ prefers references over pointers for singleton access

Rust Implementation

Rust implementation using lazy_static or once_cell crate for thread-safe initialization:

use std::sync::{Arc, Mutex};
use once_cell::sync::Lazy;

// Using once_cell for lazy static initialization
static SINGLETON: Lazy<Arc<Mutex<Singleton>>> = Lazy::new(|| {
    println!("Creating singleton instance");
    Arc::new(Mutex::new(Singleton {
        value: String::from("singleton"),
    }))
});

struct Singleton {
    value: String,
}

impl Singleton {
    fn get_instance() -> Arc<Mutex<Singleton>> {
        Arc::clone(&SINGLETON)
    }
    
    fn do_something(&self) {
        println!("Singleton method called with value: {}", self.value);
    }
    
    fn set_value(&mut self, value: String) {
        self.value = value;
    }
}

fn main() {
    // Both variables reference the same instance
    let s1 = Singleton::get_instance();
    let s2 = Singleton::get_instance();
    
    println!("Same instance? {}", Arc::ptr_eq(&s1, &s2));
    
    {
        let mut instance = s1.lock().unwrap();
        instance.set_value(String::from("modified"));
        instance.do_something();
    }
    
    {
        let instance = s2.lock().unwrap();
        println!("s2 value: {}", instance.value);
    }
}

// Alternative: Using std::sync::Once for more control
use std::sync::Once;

struct ConfigManager {
    config: String,
}

static mut CONFIG_MANAGER: Option<ConfigManager> = None;
static INIT: Once = Once::new();

impl ConfigManager {
    fn get_instance() -> &'static ConfigManager {
        unsafe {
            INIT.call_once(|| {
                println!("Initializing ConfigManager");
                CONFIG_MANAGER = Some(ConfigManager {
                    config: String::from("default config"),
                });
            });
            CONFIG_MANAGER.as_ref().unwrap()
        }
    }
    
    fn get_config(&self) -> &str {
        &self.config
    }
}

// Usage in another function
fn use_config() {
    let config1 = ConfigManager::get_instance();
    let config2 = ConfigManager::get_instance();
    
    println!("Config: {}", config1.get_config());
    println!("Same instance? {}", std::ptr::eq(config1, config2));
}

Key Points:

  • once_cell crate provides safe lazy static initialization
  • Arc<Mutex<T>> ensures thread-safe shared ownership and mutability
  • Rust’s ownership system prevents many common Singleton pitfalls
  • std::sync::Once provides low-level initialization control
  • Cargo.toml dependency: once_cell = "1.19"

Comparison Table

LanguageThread Safety MechanismComplexityBest For
C#Lazy<T>LowEnterprise applications
Node.jsSingle-threaded (no explicit locking)Very LowWeb applications
Pythonthreading.Lock or metaclassMediumData processing, scripting
Gosync.OnceLowConcurrent systems
C++Static local variables (C++11+)MediumSystem programming
Rustonce_cell + Arc<Mutex>Medium-HighSafe concurrent systems

Testing Singleton Implementations

Here’s a general approach to test Singleton implementations across languages:

# Python example - similar concepts apply to other languages
import threading
import unittest

class TestSingleton(unittest.TestCase):
    def test_single_instance(self):
        """Test that only one instance is created"""
        s1 = Singleton()
        s2 = Singleton()
        self.assertIs(s1, s2)
    
    def test_shared_state(self):
        """Test that state is shared between references"""
        s1 = Singleton()
        s2 = Singleton()
        
        s1.value = "test"
        self.assertEqual(s2.value, "test")
    
    def test_thread_safety(self):
        """Test thread-safe initialization"""
        instances = []
        
        def create_instance():
            instances.append(Singleton())
        
        threads = [threading.Thread(target=create_instance) 
                   for _ in range(10)]
        
        for thread in threads:
            thread.start()
        for thread in threads:
            thread.join()
        
        # All instances should be the same
        self.assertTrue(all(inst is instances[0] for inst in instances))

if __name__ == '__main__':
    unittest.main()

Common Pitfalls and Solutions

  1. Serialization Issues: Deserializing a singleton can create new instances. Implement custom serialization methods to return the existing instance.
  2. Reflection Attacks: In languages like Java and C#, reflection can break singleton. Use enums (Java) or sealed classes with proper protection.
  3. Testing Difficulties: Singletons make unit testing hard. Consider dependency injection or using interfaces to allow mock implementations.
  4. Thread Safety Overhead: Don’t add thread safety if your application is single-threaded. Choose eager initialization for simple cases.

Best Practices Summary

  • Always consider thread safety in multi-threaded environments
  • Make constructors private to prevent external instantiation
  • Delete or disable copy constructors and assignment operators
  • Use language-specific idioms (Lazy<T> in C#, sync.Once in Go, etc.)
  • Document why Singleton is used and its lifecycle
  • Consider lazy vs eager initialization based on your use case
  • Implement proper cleanup if resources need to be released

These implementations provide solid foundations for using the Singleton pattern in production code. Remember to adapt them based on your specific requirements and always consider whether Singleton is the right pattern for your use case.

Still stuck? Contact

How can we help?

Leave a Reply

Your email address will not be published. Required fields are marked *

All Rights Reserved 2025.