Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Prototype Pattern

Clone existing objects instead of creating new ones - save time and resources!

Now let’s dive into the Prototype Pattern - a creational design pattern that lets you create new objects by copying existing ones (prototypes) instead of creating them from scratch.

Imagine you’re ordering custom pizzas. Instead of describing each pizza from scratch every time, you can say “I want the same as last time, but with extra cheese!” The Prototype Pattern works the same way!

The Prototype Pattern lets you create new objects by cloning existing instances. Instead of going through expensive object creation, you copy a prototype and customize it.

The Prototype Pattern is useful when:

  1. Object creation is expensive - Database queries, network calls, complex calculations
  2. You need many similar objects - Objects with similar structure but different values
  3. You want to avoid subclassing - Don’t want to create a class hierarchy
  4. Runtime configuration - Objects need to be configured at runtime
  5. You want to hide creation complexity - Client doesn’t need to know how objects are created

What Happens If We Don’t Use Prototype Pattern?

Section titled “What Happens If We Don’t Use Prototype Pattern?”

Without the Prototype Pattern, you might:

  • Recreate expensive objects - Waste time and resources on expensive initialization
  • Duplicate initialization code - Same setup code repeated everywhere
  • Create unnecessary subclasses - Class explosion for slight variations
  • Tight coupling - Client code depends on concrete classes
  • Performance issues - Slow object creation impacts application performance

Let’s start with a super simple example that anyone can understand!

Diagram

Here’s how the Prototype Pattern works in practice - showing the cloning process:

sequenceDiagram
    participant Client
    participant Prototype as PizzaPrototype
    participant Clone1 as CustomPizza1
    participant Clone2 as CustomPizza2
    
    Note over Client,Clone2: Expensive initialization happens once
    
    Client->>Prototype: create_prototype()
    activate Prototype
    Note over Prototype: Expensive setup:<br/>- Database queries<br/>- Network calls<br/>- Complex calculations
    Prototype-->>Client: prototype instance
    deactivate Prototype
    
    Note over Client,Clone2: Fast cloning for similar objects
    
    Client->>Prototype: clone()
    activate Prototype
    Prototype->>Clone1: create copy
    activate Clone1
    Clone1-->>Prototype: cloned instance
    deactivate Clone1
    Prototype-->>Client: Clone1
    deactivate Prototype
    
    Client->>Clone1: customize(toppings)
    activate Clone1
    Clone1-->>Client: customized
    deactivate Clone1
    
    Client->>Prototype: clone()
    activate Prototype
    Prototype->>Clone2: create copy
    activate Clone2
    Clone2-->>Prototype: cloned instance
    deactivate Clone2
    Prototype-->>Client: Clone2
    deactivate Prototype
    
    Note over Client,Clone2: Much faster than<br/>creating from scratch!

You’re building a pizza ordering system where customers can order custom pizzas. Creating each pizza from scratch involves expensive operations (loading templates, fetching prices, validating ingredients). Without Prototype Pattern:

Problems:

  • Expensive operations repeated for every pizza
  • Slow performance when creating many similar pizzas
  • Wasted resources on redundant operations
  • No way to reuse expensive initialization
classDiagram
    class PizzaPrototype {
        <<abstract>>
        +clone() PizzaPrototype
        +customize(toppings) void
    }
    class Pizza {
        -size: str
        -crust: str
        -toppings: List
        +clone() Pizza
        +customize(toppings) void
        +describe() str
    }
    class MargheritaPrototype {
        +clone() Pizza
    }
    class PepperoniPrototype {
        +clone() Pizza
    }
    class Client {
        +create_pizzas() void
    }
    
    PizzaPrototype <|-- Pizza : implements
    Pizza <|-- MargheritaPrototype : extends
    Pizza <|-- PepperoniPrototype : extends
    Client --> PizzaPrototype : clones
    
    note for PizzaPrototype "Expensive initialization<br/>happens once"
    note for Pizza "Clone is fast -<br/>just copy data"

Real-World Software Example: Document Template System

Section titled “Real-World Software Example: Document Template System”

Now let’s see a realistic software example - a document generation system where creating documents involves expensive database queries and template loading.

You’re building a document generation system. Creating each document involves loading templates from database, fetching user data, and formatting. Without Prototype Pattern:

Problems:

  • Expensive template loading repeated for every document
  • Slow performance when generating many documents
  • Wasted resources on redundant operations
  • No way to reuse template loading

There are several ways to implement the Prototype Pattern:

Shallow Copy: Copies object references (faster but shared references)

Deep Copy: Copies all nested objects (slower but independent)

A registry pattern to manage prototypes:


Use Prototype Pattern when:

Object creation is expensive - Database queries, network calls, complex calculations
You need many similar objects - Objects with similar structure but different values
You want to avoid subclassing - Don’t want to create a class hierarchy
Runtime configuration - Objects need to be configured at runtime
You want to hide creation complexity - Client doesn’t need to know how objects are created

Don’t use Prototype Pattern when:

Object creation is cheap - If creation is fast, cloning adds unnecessary complexity
Objects are very different - If objects differ significantly, cloning doesn’t help
You need deep inheritance - Subclassing might be better
Cloning is complex - If cloning is as expensive as creation, pattern doesn’t help


Mistake 1: Shallow Copy When Deep Copy is Needed

Section titled “Mistake 1: Shallow Copy When Deep Copy is Needed”

Mistake 2: Not Implementing Clone Properly

Section titled “Mistake 2: Not Implementing Clone Properly”

  1. Performance - Cloning is faster than expensive object creation
  2. Resource Efficiency - Reuse expensive initialization
  3. Flexibility - Clone and customize objects at runtime
  4. Reduced Subclassing - Don’t need class hierarchy for variations
  5. Hide Complexity - Client doesn’t need to know creation details

Prototype Pattern is a creational design pattern that lets you create new objects by copying existing instances (prototypes) instead of creating them from scratch.

  • Expensive object creation - Clone is faster than expensive initialization
  • Many similar objects - Objects with similar structure but different values
  • Avoid subclassing - Don’t need class hierarchy for variations
  • Runtime configuration - Objects configured at runtime
  • Resource efficiency - Reuse expensive initialization
  1. Create prototype - Create an instance with expensive initialization
  2. Register prototype - Store prototype in registry (optional)
  3. Clone prototype - Create copy of prototype (fast!)
  4. Customize clone - Modify cloned object as needed
Client → Prototype.clone() → Clone Instance
  • Prototype Interface - Defines clone method
  • Concrete Prototype - Implements cloning
  • Client - Uses prototype to create objects
  • Registry - Manages prototypes (optional)
class Pizza:
def __init__(self):
# Expensive initialization
self._load_template()
def clone(self):
return copy.deepcopy(self) # Fast clone!
# Usage
prototype = Pizza() # Expensive - happens once
pizza1 = prototype.clone() # Fast!
pizza2 = prototype.clone() # Fast!

✅ Expensive object creation
✅ Many similar objects needed
✅ Want to avoid subclassing
✅ Runtime configuration required
✅ Need to hide creation complexity

❌ Object creation is cheap
Objects are very different
❌ Need deep inheritance
❌ Cloning is as expensive as creation

  • Prototype Pattern = Clone existing objects instead of creating new
  • Prototype = Template object with expensive initialization
  • Clone = Fast copy operation
  • Benefit = Performance and resource efficiency
  • Use Case = Expensive object creation with similar objects
class Prototype:
def clone(self):
return copy.deepcopy(self)
# Usage
prototype = Prototype() # Expensive initialization
clone1 = prototype.clone() # Fast!
clone2 = prototype.clone() # Fast!
  • Prototype Pattern clones existing objects
  • It’s useful when creation is expensive
  • Use deep copy for objects with mutable nested structures
  • Clone is faster than expensive initialization
  • Don’t use it when creation is cheap - avoid over-engineering!

What to say:

“Prototype Pattern is a creational design pattern that lets you create new objects by copying existing instances instead of creating them from scratch. It’s useful when object creation is expensive, and you need many similar objects.”

Why it matters:

  • Shows you understand the fundamental purpose
  • Demonstrates knowledge of when to use it
  • Indicates you can explain concepts clearly

Must mention:

  • Expensive object creation - Database queries, network calls
  • Many similar objects - Objects with similar structure
  • Avoid subclassing - Don’t want class hierarchy
  • Runtime configuration - Objects configured at runtime

Example scenario to give:

“I’d use Prototype Pattern when building a document generation system. Loading templates from database is expensive. Instead of loading the template every time, I create a prototype once, then clone it for each document with different user data.”

Must discuss:

  • Shallow Copy: Copies object references (faster but shared references)
  • Deep Copy: Copies all nested objects (slower but independent)
  • When to use each: Deep copy for mutable nested structures

Example to give:

“In Python, I use copy.deepcopy() for objects with mutable nested structures like lists or dictionaries. Shallow copy would share references, causing bugs when modifying cloned objects.”

Benefits to mention:

  • Performance - Cloning is faster than expensive creation
  • Resource Efficiency - Reuse expensive initialization
  • Flexibility - Clone and customize at runtime
  • Reduced Subclassing - Don’t need class hierarchy

Trade-offs to acknowledge:

  • Complexity - Need to implement cloning correctly
  • Memory - Prototypes consume memory
  • Not always faster - If creation is cheap, cloning adds overhead

Q: “What’s the difference between Prototype Pattern and Factory Pattern?”

A:

Factory Pattern creates objects based on input, while Prototype Pattern clones existing objects. Factory is used when you need different types of objects, Prototype is used when you need many similar objects and creation is expensive.”

Q: “When would you use shallow copy vs deep copy?”

A:

“I use shallow copy when objects don’t have mutable nested structures - it’s faster. I use deep copy when objects have mutable nested structures like lists or dictionaries - it ensures independent copies and prevents bugs from shared references.”

Q: “How do you implement Prototype Pattern in a multi-threaded environment?”

A:

“I ensure the clone method is thread-safe. The prototype itself should be immutable or protected with synchronization. When cloning, I create a new instance with copied data, which is naturally thread-safe since each clone is independent.”

Before your interview, make sure you can:

  • Define Prototype Pattern clearly in one sentence
  • Explain when to use it (with examples)
  • Describe shallow vs deep copy
  • Implement Prototype Pattern from scratch
  • Compare with other creational patterns
  • List benefits and trade-offs
  • Identify common mistakes
  • Give 2-3 real-world examples
  • Discuss thread safety considerations

Remember: Prototype Pattern is about cloning expensive objects efficiently - clone once, customize many times! 🎯