Understanding the Object Factory Design Pattern with Python Examples
This article explains the Object Factory design pattern, its benefits such as decoupling, extensibility, and centralized instance management, and demonstrates five practical Python examples covering basic product creation, configuration‑driven factories, logger factories, singleton factories, and object caching factories.
The Object Factory (also known as a factory pattern) is a software design pattern that centralizes object creation, allowing callers to obtain instances without depending on concrete classes, thereby improving decoupling, extensibility, and manageability of object lifecycles.
Key advantages include:
Decoupling : Callers request objects through the factory rather than instantiating concrete classes directly.
Extensibility : New product types can be added by extending the factory logic without modifying client code.
Managed instantiation : Factories can handle caching, reuse, or configuration‑driven creation of objects.
Below are five Python examples illustrating different uses of the Object Factory pattern.
Example 1: Creating different product types
class Product:
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
class ProductFactory:
@staticmethod
def create_product(product_type, name):
if product_type == "A":
return ProductA(name)
elif product_type == "B":
return ProductB(name)
else:
raise ValueError("Invalid product type")
class ProductA(Product):
def __init__(self, name):
super().__init__(name)
class ProductB(Product):
def __init__(self, name):
super().__init__(name)
# Usage
product_factory = ProductFactory()
product_a = product_factory.create_product("A", "Apple")
product_b = product_factory.create_product("B", "Banana")Example 2: Factory driven by a configuration file
import json
class Product:
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
class ProductFactory:
def __init__(self, config_file):
self.config = self.load_config(config_file)
@staticmethod
def load_config(config_file):
with open(config_file, 'r') as f:
return json.load(f)
def create_product(self, name):
product_type = self.config.get("product_type", "default")
if product_type == "A":
return ProductA(name)
elif product_type == "B":
return ProductB(name)
else:
return Product(name)
class ProductA(Product):
def __init__(self, name):
super().__init__(name)
class ProductB(Product):
def __init__(self, name):
super().__init__(name)
# Usage
product_factory = ProductFactory("config.json")
product = product_factory.create_product("Apple")Example 3: Factory method for different logger types
import logging
class Logger:
def log(self, message):
pass
class FileLogger(Logger):
def log(self, message):
# write to file
pass
class DatabaseLogger(Logger):
def log(self, message):
# write to database
pass
class LoggerFactory:
@staticmethod
def create_logger(logger_type):
if logger_type == "file":
return FileLogger()
elif logger_type == "database":
return DatabaseLogger()
else:
raise ValueError("Invalid logger type")
# Usage
logger_factory = LoggerFactory()
logger = logger_factory.create_logger("file")
logger.log("Log message")Example 4: Singleton factory
class Singleton:
def __init__(self):
pass
class SingletonFactory:
_instance = None
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = Singleton()
return cls._instance
# Usage
singleton = SingletonFactory.get_instance()Example 5: Factory with object caching
class Product:
def __init__(self, name):
self.name = name
class ProductFactory:
_product_cache = {}
@staticmethod
def create_product(name):
if name in ProductFactory._product_cache:
return ProductFactory._product_cache[name]
else:
product = Product(name)
ProductFactory._product_cache[name] = product
return product
# Usage
product_factory = ProductFactory()
product_a = product_factory.create_product("A")
product_b = product_factory.create_product("B")
product_a_cached = product_factory.create_product("A") # retrieved from cacheThese examples illustrate how the Object Factory pattern can be adapted to various scenarios such as simple product creation, configuration‑driven factories, logger creation, singleton management, and caching, enabling flexible and maintainable code architecture.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.