Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Architectural Elegance in Python: Implementing Singleton and Factory Patterns Effectively

Tech Sep 3 2

The Singleton Pattern: Managing Shared State

In Python, enforcing a single instantiation across an application lifecycle often relies on language-level execution behaviors. Because Python modules are executed exactly once per interpreter session, importing a module inherently guarantees that its top-level definitions remain unique across the entire runtime. Leveraging this characteristic allows developers to construct implicit singletons without external dependencies or complex initialization logic.

# infrastructure.py
class ConnectionPool:
    def __init__(self):
        self.connections = []
        self.pool_capacity = 5
        
    def acquire(self):
        if len(self.connections) < self.pool_capacity:
            self.connections.append(f"conn-{len(self.connections)}")
        return self.connections[-1]

pool_instance = ConnectionPool()

Any submodule importing infrastructure receives the exact same pool_instance object. This approach eliminates redundant object allocation, guarantees consistent state access, and proves highly effective for configuration loaders, cache layers, or resource managers.

Thread-Safe Implementation

When explicit class-based singletons are required, concurrent access during initialization can trigger race conditions. The standard defensive strategy combines Python's __new__ hook with a mutual exclusion lock. A dual-check mechanism avoids blocking threads after the target object has already been allocated.

import threading

class TaskScheduler:
    _instance = None
    _lock = threading.Lock()
    _bootstrapped = False

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._bootstrapped = True
        return cls._instance

    def __init__(self):
        if not self._bootstrapped:
            self.queue = []
            self._bootstrapped = True

    def schedule(self, task_id: str):
        self.queue.append(task_id)
        return f"Scheduled {task_id}"

scheduler = TaskScheduler()
print(scheduler.schedule("process-alpha"))

The explicit _bootstrapped flag separates memory allocation from constructor execution, preventing multiple runs of initialization code under heavy concurrency. This pattern maintains strict object identity while guaranteeing thread safety without compromising performance.

Factory Patterns: Decoupling Object Creation

Creational patterns delegate instantiation responsibilities away from client code, reducing coupling between interfaces and concrete implementations. The Factory pattern provides a unified routing layer for generating specialized objects based on dynamic input parameters.

Conditional Dispatch to Mapping Tables

A naive implementation typically relies on sequential branching. While functional for small scopes, this structure violates the Open/Closed Principle, forcing repeated modifications to the factory whenever new product variants are introduced.

class ReportGenerator:
    def generate_report(self, data: list) -> str:
        raise NotImplementedError

class PdfReport(ReportGenerator):
    def generate_report(self, data: list) -> str:
        return f"[PDF] Compiled report with {len(data)} entries"

class CsvReport(ReportGenerator):
    def generate_report(self, data: list) -> str:
        return f"[CSV] Exported {len(data)} records"

def create_report(format_type: str) -> ReportGenerator:
    if format_type == "pdf":
        return PdfReport()
    elif format_type == "csv":
        return CsvReport()
    raise ValueError(f"Unsupported format: {format_type}")

Replacing conditional chains with a dictionary lookup improves readability, reduces cyclomatic complexity, and centralizes type resolution. Direct hash-map indexing eliminates sequential comparisons and accelerates dispatch throughput.

class ReportFactory:
    _registry = {
        "pdf": PdfReport,
        "csv": CsvReport
    }

    @classmethod
    def build(cls, fmt: str) -> ReportGenerator:
        generator_class = cls._registry.get(fmt)
        if not generator_class:
            raise KeyError(f"No handler registered for '{fmt}'")
        return generator_class()

Extending this system now requires only adding new subclasses and appending entries to the registry dictionary, leaving the factory routing logic entirely untouched.

Dynamic Registration System

For highly modular architectures, embedding the registry directly into a static class can create rigid dependencies. A decentralized approach stores mappings within an instance, enabling hot-swapping and plugin-style expansion.

class Dispatcher:
    def __init__(self):
        self.strategies = {}

    def register(self, name: str, strategy_class):
        self.strategies[name] = strategy_class

    def execute(self, name: str, payload: dict):
        if name not in self.strategies:
            raise LookupError(f"Unknown strategy: {name}")
        instance = self.strategies[name]()
        return instance.process(payload)

class EncryptionStrategy:
    def process(self, payload: dict) -> str:
        return f"Encrypted: {payload['text']}"

class CompressionStrategy:
    def process(self, payload: dict) -> str:
        return f"Compressed: {payload['text'].upper()}"

bus = Dispatcher()
bus.register("encrypt", EncryptionStrategy)
bus.register("compress", CompressionStrategy)

result = bus.execute("compress", {"text": "sensitive-data"})
print(result)

This architecture promotes strict separation of concerns. Independent modules can register their own handlers dynamically, supporting runtime configuration changes and eliminating hard-coded type relationships.

Abstract Factory with Strict Contracts

When systems require assembling families of related objects without exposing concrete constructors, Abstract Factories enforce structural consistency through inheritance hierarchies. Integrating this with Python's abc module establishes runtime validation that guarantees implementation completeness.

from abc import ABC, abstractmethod

class VehiclePart(ABC):
    @abstractmethod
    def assemble(self) -> str: pass

class SedanChassis(VehiclePart):
    def assemble(self) -> str:
        return "Sedan chassis assembled"

class SuvEngine(VehiclePart):
    def assemble(self) -> str:
        return "SUV engine mounted"

class PartFactory(ABC):
    @abstractmethod
    def create_chassis(self) -> VehiclePart: pass
    @abstractmethod
    def create_engine(self) -> VehiclePart: pass

class CarManufacturer(PartFactory):
    def create_chassis(self) -> VehiclePart:
        return SedanChassis()
    
    def create_engine(self) -> VehiclePart:
        return SuvEngine()

manufacturer = CarManufacturer()
chassis_component = manufacturer.create_chassis()
engine_component = manufacturer.create_engine()

print(chassis_component.assemble())
print(engine_component.assemble())

By defining abstract base classes for both products and factories, the framework ensures that every concrete manufacturer implements the complete assembly pipeline. Introducing a new vehicle lineage involves instantiating a dedicated factory subclass without altering existing manufacturing workflows. This isolation of responsibilities streamlines unit testing, facilitates dependency injection, and simplifies long-term system evolution.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.