Singleton
1. Overview
- most hated design pattern
- Motivation
- Some components make sense to be initialized only once
- e.g. Database repository
- Object factory
- Why? Initializer call is expensive
- Or resource available only available once
- We provide everyone with same instance
- Prevent everyone from creating copies
- Take care of lazy instantiation
- Solution
- A component which is intantiated only once
2. Singleton Allocator
class Database:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new(cls, *args, **kwargs)
return cls._instance
- Only good enough if nothing in
__init__. - May not work most time
3. Singleton Decorator
def singleton(class_):
instances = {}
def get_instance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
@singleton
class Database:
.......
4. Singleton Metaclass
- alternative to decorator
```python class Singleton(type): _instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*arg, **kwargs)
return cls._instances[cls]
class Database(metaclass=Singleton): ..... ```
5. Monostate
Create a shared state and assign it in __init__
class Monostate:
_shared_state = {}
def __new__(cls, *args, **kwargs)
obj = super().__new__(*args, **kwargs)
obj.__dict__ = self._shared_state
return obj
class CEO(Monostate):
....
- But not the best approach. Stick with metaclass or decorator
6. Singleton Testability
7. Summary
- Different realization - custom allocator, decorator or metaclass (best)