|
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 | +# ============================================================================= |
2 | 17 | class SingletonMeta(type): |
| 18 | + """A thread-safe implementation of Singleton.""" |
3 | 19 | _instance = None |
| 20 | + _lock: Lock = Lock() |
| 21 | + |
4 | 22 | 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) |
7 | 26 | return cls._instance |
8 | 27 |
|
| 28 | + |
9 | 29 | class Logger(metaclass=SingletonMeta): |
10 | | - def log(self, msg): |
| 30 | + """A simple logger class using Singleton pattern.""" |
| 31 | + def log(self, msg: str) -> None: |
11 | 32 | print(f"[LOG]: {msg}") |
12 | 33 |
|
13 | | -logger1 = Logger() |
14 | | -logger2 = Logger() |
15 | | -assert logger1 is logger2 |
| 34 | + |
| 35 | +# ============================================================================= |
| 36 | +# 2. FACTORY PATTERN |
| 37 | +# ============================================================================= |
16 | 38 | 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 | + |
19 | 43 |
|
20 | 44 | class Dog(Animal): |
21 | | - def speak(self): |
| 45 | + def speak(self) -> str: |
22 | 46 | return "Woof!" |
23 | 47 |
|
| 48 | + |
24 | 49 | class Cat(Animal): |
25 | | - def speak(self): |
| 50 | + def speak(self) -> str: |
26 | 51 | return "Meow!" |
27 | 52 |
|
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") |
34 | 53 |
|
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