100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Python

Singleton and Factory Patterns

Learn how Singleton guarantees a single instance and how Factory Method delegates object creation to a central point.

Design Patterns — Creational & StructuralBeginner10 min readJul 8, 2026
Analogies

Introduction

Singleton and Factory Method are two of the most widely used Creational design patterns. Singleton ensures a class has only one instance and provides a global point of access to it. Factory Method defines an interface (or function) for creating an object but lets subclasses, or a parameterized creator function, decide which concrete class to instantiate. Both patterns exist to control 'how' and 'when' objects come into being, rather than leaving instantiation scattered throughout the codebase.

🏏

Cricket analogy: Singleton is like a team having exactly one official scorer whose scorecard is the single source of truth for the match, while Factory Method is like a selector function that decides which type of bowler to bring on, pacer, spinner, or all-rounder, based on the situation, without the captain hardcoding the choice.

Explanation

A Singleton is useful when exactly one object is needed to coordinate actions across a system — for example, a configuration manager, a logging service, or a connection pool. It typically works by making the constructor private (or restricted) and exposing a static/class-level accessor that creates the instance on first use and returns the cached instance thereafter. Overuse of Singleton is a common anti-pattern because it introduces global state, which makes unit testing harder and can hide dependencies.

🏏

Cricket analogy: A Singleton is useful for a single official scoreboard that coordinates runs and wickets across the ground; it works by restricting who can update it directly and exposing one official channel that creates the record on first ball and returns the same running total thereafter, though over-relying on one global scoreboard for local team stats makes independent analysis harder.

Factory Method, by contrast, addresses a different problem: a class cannot anticipate which concrete class of object it needs to create. Instead of littering the codebase with direct calls to concrete constructors (e.g., PDFExporter(), CSVExporter()), client code calls a factory with a parameter (e.g., create_exporter("csv")), and the factory encapsulates the decision of which concrete class to instantiate. This keeps object-creation logic in one place and makes it easy to add new types without modifying client code — an application of the Open/Closed Principle.

🏏

Cricket analogy: Factory Method addresses picking the right bowler for a situation: instead of the captain hardcoding 'bring on Bumrah' every time, they call a selector with a parameter like 'need a wicket' or 'need to save runs,' and the selector encapsulates which bowler type, pace or spin, actually gets the ball.

Example

python
import threading

# --- Singleton: thread-safe lazy instantiation ---
class ConfigManager:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance.settings = {}
        return cls._instance

    def set(self, key, value):
        self.settings[key] = value


# --- Factory Method: delegate creation based on a parameter ---
class Exporter:
    def export(self, data):
        raise NotImplementedError

class CSVExporter(Exporter):
    def export(self, data):
        return ",".join(data)

class JSONExporter(Exporter):
    def export(self, data):
        import json
        return json.dumps(data)

def create_exporter(kind: str) -> Exporter:
    exporters = {"csv": CSVExporter, "json": JSONExporter}
    if kind not in exporters:
        raise ValueError(f"Unknown exporter: {kind}")
    return exporters[kind]()


if __name__ == "__main__":
    a = ConfigManager()
    b = ConfigManager()
    a.set("debug", True)
    print(a is b, b.settings)  # True {'debug': True}

    exporter = create_exporter("json")
    print(exporter.export(["x", "y", "z"]))

Analysis

In the Singleton example, __new__ is overridden so that only one instance is ever created; the lock guards against a race condition where two threads might otherwise both see _instance is None at the same time. In the Factory Method example, create_exporter is the single place that knows how to map a string to a concrete Exporter subclass — client code never calls CSVExporter() or JSONExporter() directly. Adding a new format, such as XML, means adding one class and one dictionary entry, without touching any code that calls create_exporter.

🏏

Cricket analogy: In the scoreboard Singleton, only one official record is ever created, guarded so two officials updating it at the exact same ball don't create conflicting totals; in the bowler-selector Factory, select_bowler is the single place mapping situation to bowler type, so adding a new bowling style, like a mystery spinner, means adding one class without touching the captain's calling code.

A common mistake is conflating Singleton with Factory: Singleton constrains 'how many' instances exist, while Factory Method constrains 'which class' gets instantiated. They can be combined (a Factory that itself is a Singleton) but they solve orthogonal problems. Another common mistake is implementing Singleton without thread safety, which in multi-threaded environments can accidentally create two 'singleton' instances.

🏏

Cricket analogy: Confusing Singleton with Factory is like confusing 'there is only one official scorer' with 'the selector decides pace or spin'; a scoring system could combine both, one Singleton scorer that internally uses a Factory to instantiate the right delivery-type record, but they solve different problems, and a scorer implemented without safeguards against simultaneous updates from two officials can produce two conflicting 'official' totals.

Key Takeaways

  • Singleton guarantees exactly one instance of a class and a global access point to it.
  • Factory Method centralizes the decision of which concrete class to instantiate based on input.
  • Singleton controls instance count; Factory Method controls instance type — they are independent concerns.
  • Overusing Singleton introduces hidden global state that complicates testing.
  • Factory Method supports the Open/Closed Principle by letting new types be added without modifying client code.

Practice what you learned

Was this page helpful?

Topics covered

#Python#SoftwareEngineeringStudyNotes#SoftwareEngineering#SingletonAndFactoryPatterns#Singleton#Factory#Patterns#Explanation#StudyNotes#SkillVeris