Singleton Pattern

The Singleton is a creational design pattern that ensures a class has only one instance throughout the application lifetime and provides a global point of access to it. It is useful for managing shared resources (e.g., logger, configuration, database connection) where multiple instances would be wasteful or inconsistent.

Key Principles

  • Eager/Lazy Initialization: Create instance on first access (lazy) or upfront (eager).
  • Thread-Safety: Handle concurrent access (e.g., locks in multi-threaded env).
  • Global Access: Instance as a class attribute or module-level variable.

Structure

  • Singleton Class: Private constructor; static method (e.g., get_instance()) returns the single instance.
  • Client: Calls factory method instead of constructor.

Python Example: Logger Singleton

import threading

class Logger:
    _instance = None
    _lock = threading.Lock()  # For thread-safety

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super(Logger, cls).__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if self._initialized:
            return
        self.logs = []
        self._initialized = True

    def log(self, message):
        self.logs.append(message)
        print(f"Logged: {message}")

    def get_logs(self):
        return self.logs.copy()

# Usage (Client Code)
if __name__ == "__main__":
    logger1 = Logger()
    logger1.log("First message")

    logger2 = Logger()  # Same instance
    logger2.log("Second message")

    print(f"Logs: {logger2.get_logs()}")  # ['First message', 'Second message']
    print(f"Same instance: {logger1 is logger2}")  # True

Output:

Logged: First message
Logged: Second message
Logs: ['First message', 'Second message']
Same instance: True

When to Use Singleton

  • Shared Resources: Global config, cache, or logger.
  • Lazy Loading: Instance created only when needed.
  • Avoid: In multi-threaded/singleton-heavy apps (use dependency injection instead for testability).

Summary: Singleton guarantees one instance per class with global access, preventing duplication while allowing lazy, thread-safe creation.