Creational Patterns
18 min
Creational patterns control HOW objects get created — useful once "just call the constructor directly" isn't flexible enough. The Factory pattern centralizes creation logic behind a function, so callers ask for what they want by name/kind instead of knowing which exact class to instantiate:
def create_shape(kind, *args):
if kind == "rectangle":
return Rectangle(*args)
elif kind == "circle":
return Circle(*args)
else:
raise ValueError(f"Unknown shape kind: {kind}")
shape = create_shape("rectangle", 3, 4)
The caller never writes Rectangle(3, 4) directly — if you ever need to
change how rectangles get constructed (add a caching layer, a default
argument, validation), there's exactly one place to change it.
The calling code only deals with (kind, *args) tuples -- it never imports or references Rectangle/Circle directly, which is exactly the decoupling the Factory pattern is for.
The Singleton pattern guarantees a class has AT MOST one instance, and every "creation" after the first just returns the existing one — useful for things like a shared config object or connection pool, where having two independent instances would be a bug, not a feature:
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.settings = {}
return cls._instance
a = Config()
b = Config()
print(a is b) # True -- literally the same object, not just equal
__new__ (not __init__) is where object CREATION happens in Python —
overriding it is what lets the class intercept "someone's asking for a
new instance" and hand back the existing one instead. Singletons are
somewhat controversial in practice (they're effectively global mutable
state, which makes testing harder) — worth knowing, but reach for
dependency injection instead where you can.
Given `Shape`/`Rectangle`/`Circle` below, write `create_shape(kind, *args)` (the Factory pattern): return `Rectangle(*args)` if `kind == 'rectangle'`, `Circle(*args)` if `kind == 'circle'`, otherwise raise `ValueError`.
Implement `Config.__new__` (the Singleton pattern): the first call creates a real instance with an empty `settings` dict; every later call to `Config()` must return that SAME instance, not a new one.
What problem does the Factory pattern solve?
You can implement the Factory pattern to centralize object creation, and the Singleton pattern to guarantee a class has at most one shared instance.