Factory Method Pattern
The Factory Method is a creational design pattern that defines an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. It promotes loose coupling by delegating the instantiation logic to subclasses.
Key Principles
- Encapsulate object creation: Hide "how" objects are created.
- Open/Closed Principle: Extend behavior (new product types) without modifying existing code.
- Dependency Inversion: Depend on abstractions (factory interface), not concrete classes.
Structure
- Product: Interface/abstract class for objects the factory creates.
- Concrete Product: Specific implementations.
- Creator (Factory): Declares the factory method (returns Product).
- Concrete Creator: Overrides factory method to return specific Concrete Product.
Python Example: Shape Factory
from abc import ABC, abstractmethod
import math
# Product Interface
class Shape(ABC):
@abstractmethod
def area(self) -> float:
pass
# Concrete Products
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return math.pi * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
class Square(Shape):
def __init__(self, side: float):
self.side = side
def area(self) -> float:
return self.side ** 2
# Creator (Factory) with Factory Method
class ShapeFactory(ABC):
@abstractmethod
def create_shape(self) -> Shape:
pass
# Template method using the factory
def compute_area(self) -> float:
shape = self.create_shape()
return shape.area()
# Concrete Creators
class CircleFactory(ShapeFactory):
def __init__(self, radius: float):
self.radius = radius
def create_shape(self) -> Shape:
return Circle(self.radius)
class RectangleFactory(ShapeFactory):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def create_shape(self) -> Shape:
return Rectangle(self.width, self.height)
class SquareFactory(ShapeFactory):
def __init__(self, side: float):
self.side = side
def create_shape(self) -> Shape:
return Square(self.side)
# Usage (client code)
if __name__ == "__main__":
circle = CircleFactory(radius=5).compute_area()
rectangle = RectangleFactory(width=4, height=6).compute_area()
square = SquareFactory(side=3).compute_area()
print(f"Circle area: {circle:.2f}") # ~78.54
print(f"Rectangle area: {rectangle}") # 24
print(f"Square area: {square}") # 9
When to Use Factory Method
- When a class can't anticipate the type of objects it needs to create.
- When you want to localize object creation knowledge in subclasses.
- To extend with new product types easily (add new factory subclass).
Summary: Factory Method lets subclasses decide which object to instantiate, keeping client code decoupled from concrete classes.