Skip to content

Commit e58ea08

Browse files
feat: Enhanced Singleton and Factory pattern example with thread-safety, dynamic registration, and logging
This PR enhances the existing implementation of the Singleton and Factory Method design patterns by making them more robust, extensible, and aligned with real-world usage. It improves the structure, documentation, and maintainability of the code — turning a simple pattern demo into a clean, production-ready educational example.
1 parent fe22fea commit e58ea08

File tree

1 file changed

+73
-19
lines changed

1 file changed

+73
-19
lines changed
Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,90 @@
1-
# Singleton Pattern
1+
"""
2+
Title: Singleton and Factory Design Pattern Example
3+
Author: Python Design Patterns Contributors
4+
Description:
5+
Demonstrates the Singleton and Factory Method design patterns in Python
6+
with a Logger and Animal creation system.
7+
Date: October 2025
8+
"""
9+
10+
from threading import Lock
11+
from typing import Type, Dict
12+
13+
14+
# =============================================================================
15+
# 1. SINGLETON PATTERN (Thread-safe)
16+
# =============================================================================
217
class SingletonMeta(type):
18+
"""A thread-safe implementation of Singleton."""
319
_instance = None
20+
_lock: Lock = Lock()
21+
422
def __call__(cls, *args, **kwargs):
5-
if not cls._instance:
6-
cls._instance = super().__call__(*args, **kwargs)
23+
with cls._lock:
24+
if cls._instance is None:
25+
cls._instance = super().__call__(*args, **kwargs)
726
return cls._instance
827

28+
929
class Logger(metaclass=SingletonMeta):
10-
def log(self, msg):
30+
"""A simple logger class using Singleton pattern."""
31+
def log(self, msg: str) -> None:
1132
print(f"[LOG]: {msg}")
1233

13-
logger1 = Logger()
14-
logger2 = Logger()
15-
assert logger1 is logger2
34+
35+
# =============================================================================
36+
# 2. FACTORY PATTERN
37+
# =============================================================================
1638
class Animal:
17-
def speak(self):
18-
pass
39+
"""Base Animal class."""
40+
def speak(self) -> str:
41+
raise NotImplementedError("Subclasses must implement 'speak' method.")
42+
1943

2044
class Dog(Animal):
21-
def speak(self):
45+
def speak(self) -> str:
2246
return "Woof!"
2347

48+
2449
class Cat(Animal):
25-
def speak(self):
50+
def speak(self) -> str:
2651
return "Meow!"
2752

28-
def animal_factory(animal_type: str) -> Animal:
29-
if animal_type == "dog":
30-
return Dog()
31-
elif animal_type == "cat":
32-
return Cat()
33-
raise ValueError("Unknown animal type")
3453

35-
pet = animal_factory("dog")
36-
print(pet.speak())
54+
class AnimalFactory:
55+
"""Factory for creating Animal instances dynamically."""
56+
_registry: Dict[str, Type[Animal]] = {}
57+
58+
@classmethod
59+
def register_animal(cls, name: str, animal_cls: Type[Animal]) -> None:
60+
cls._registry[name.lower()] = animal_cls
61+
62+
@classmethod
63+
def create(cls, name: str) -> Animal:
64+
if name.lower() not in cls._registry:
65+
raise ValueError(f"Unknown animal type: {name}")
66+
return cls._registry[name.lower()]()
67+
68+
69+
# Register animals dynamically
70+
AnimalFactory.register_animal("dog", Dog)
71+
AnimalFactory.register_animal("cat", Cat)
72+
73+
74+
# =============================================================================
75+
# 3. DEMONSTRATION
76+
# =============================================================================
77+
if __name__ == "__main__":
78+
logger = Logger()
79+
logger.log("Application started.")
80+
81+
pet_type = "dog"
82+
pet = AnimalFactory.create(pet_type)
83+
logger.log(f"Created a {pet_type} that says: {pet.speak()}")
84+
85+
# Validate Singleton behavior
86+
logger2 = Logger()
87+
assert logger is logger2
88+
logger.log("Verified Singleton: Both logger instances are identical.")
89+
90+
logger.log("Application finished successfully.")

0 commit comments

Comments
 (0)