Skip to main content

Creator

Assign object creation responsibility to the class best suited to create instances

TL;DR

The Creator pattern assigns object creation responsibility to the class that has a strong connection to the objects being created—typically through aggregation, composition, or initialization. This reduces coupling between classes and keeps creation logic close to the classes that use the created objects.

Learning Objectives

  • Understand when a class should be responsible for creating instances
  • Learn how to identify the best "creator" for a given object type
  • Apply Creator pattern rules to reduce coupling in your designs
  • Recognize when to use factories instead of direct instantiation
  • Avoid scattering creation logic throughout your codebase

Motivating Scenario

You have a Restaurant and a MenuItem class. Who should be responsible for creating MenuItem instances? If every function that needs a menu item creates one directly, you have creation logic scattered everywhere. But if the Restaurant class—which naturally manages a collection of menu items—handles creation, the logic stays centralized and easier to modify.

Core Concepts

The Creator pattern answers a fundamental question: who should be responsible for instantiating a new object? Rather than having multiple classes scattered throughout your codebase creating instances, Creator guides you to assign creation responsibility to a class that has a natural connection to the created object.

The pattern provides these rules for assigning creation responsibility:

  1. Assign to the class that aggregates, composes, or closely uses the created object. If class A contains or uses instances of class B, A is a good candidate to create B.

  2. Assign to the class that has the data to initialize the created object. If initialization requires data that only one class has, that class should create the object.

  3. Assign to the class that should logically control the lifecycle. In an e-commerce system, an Order should create its LineItems, not some external factory.

Creator works in tandem with Information Expert: the class that has the information needed to initialize an object is often the right class to create it. By keeping creation and use together, you maintain cohesion and reduce coupling to factory classes or global creation methods.

Creator Pattern: Determining Responsibility

Practical Example

Consider an order management system where Orders need to create their LineItems. Let's see how Creator guides our design:

creator_example.py
from dataclasses import dataclass
from typing import List

@dataclass
class Product:
id: str
name: str
price: float

class LineItem:
def __init__(self, product: Product, quantity: int):
self.product = product
self.quantity = quantity

def get_total(self) -> float:
return self.product.price * self.quantity

class Order:
"""Order is responsible for creating its LineItems"""
def __init__(self, order_id: str):
self.order_id = order_id
self.line_items: List[LineItem] = []

def add_item(self, product: Product, quantity: int) -> LineItem:
"""Creator responsibility: Order creates LineItems"""
line_item = LineItem(product, quantity)
self.line_items.append(line_item)
return line_item

def get_total(self) -> float:
return sum(item.get_total() for item in self.line_items)

# Usage
product1 = Product("P001", "Laptop", 999.99)
product2 = Product("P002", "Mouse", 29.99)

order = Order("ORD-001")
order.add_item(product1, 1)
order.add_item(product2, 2)

print(f"Order {order.order_id} total: ${order.get_total():.2f}")

When to Use / When Not to Use

Use
  1. Creating objects that are contained or aggregated by another class
  2. When the creator has the data needed to initialize the object
  3. For objects that logically belong to a parent object's lifecycle
  4. When you want creation logic close to where objects are used
  5. For simple object creation without complex initialization
Avoid
  1. Complex creation with multiple initialization steps
  2. Creating objects with many optional parameters
  3. Creating different implementations based on conditions
  4. When creation should be decoupled from the using class
  5. When multiple unrelated classes need to create the same type

Patterns and Pitfalls

Creator Implementation Patterns

Keep creation with containers: If a class aggregates or contains instances of another class, it should create them. An Order contains LineItems, so Order should create them.

Use Factory when Creator doesn't fit: If the Creator pattern would create tight coupling or complex responsibilities, introduce a Factory class. This is not a violation—it's a refinement.

Initialize fully in the constructor: When a creator creates an object, it should fully initialize it to a valid state. Don't create half-initialized objects that require external setup.

Mixing creation concerns: Don't mix simple object creation with complex business logic in the same method. If creation is complex, extract it to a dedicated factory method or class.

Creating objects you don't use: If a class creates an object but has no strong connection to it, question whether it should really be the creator. This is a sign to use Pure Fabrication.

Scattering creation logic: Don't have multiple classes creating the same type independently. Consolidate creation responsibility in one logical place.

Design Review Checklist

  • Is creation responsibility assigned to a class that aggregates the created objects?
  • Does the creator have all data needed to initialize the created object?
  • Are created objects fully initialized in a valid state?
  • Is creation logic localized rather than scattered?
  • Would using a Factory reduce inappropriate coupling?
  • Does the creation responsibility fit naturally with the creator's role?

Self-Check

  1. What's the primary rule for assigning creation responsibility? Assign it to the class that aggregates, composes, or most closely uses the created object.

  2. How does Creator relate to Information Expert? Both patterns look at what information a class has. The creator has initialization information; the object expert has operational information.

  3. When should you use a Factory instead of Creator? When the creator would need to depend on many unrelated classes, or when creating different implementations based on conditions, extract creation to a Factory.

info

One Takeaway: Keep object creation responsibility close to the classes that aggregate or use the created objects. This maintains cohesion and reduces coupling between unrelated parts of your system.

Next Steps

References

  1. GRASP (Object-Oriented Design) - Wikipedia ↗️
  2. Applying UML and Patterns by Craig Larman ↗️