Design Patterns Prototype
The Prototype pattern lets you copy an existing object instead of building a new one from scratch. Think of it like a photocopier — you place one original document and press copy. The machine produces an identical duplicate without you typing everything again.
This pattern belongs to the Creational category, meaning it deals with how objects are created. When creating a new object is expensive or complex, Prototype gives you a faster path by cloning an already-configured one.
The Real-World Idea Behind Prototype
Imagine a game studio building a city with 500 identical lamp posts. Designing each lamp post from scratch — choosing height, color, light radius, shadow — wastes enormous time. The artist builds one perfect lamp post, then clones it 499 times and places each copy in the map.
The Prototype pattern works exactly the same way in code.
Visual Diagram: How Prototype Works
+---------------------------+
| Original Object |
| (Fully configured) |
| color: "gold" |
| height: 5m |
| lightRadius: 10m |
+---------------------------+
|
| .clone()
▼
+---------------------------+ +---------------------------+
| Clone A | | Clone B |
| color: "gold" | | color: "silver" |
| height: 5m | | height: 5m |
| lightRadius: 10m | | lightRadius: 10m |
+---------------------------+ +---------------------------+
(used as-is) (one property changed)
Clone B only changed the color. Every other property copied automatically. This is the power of Prototype.
Key Terms You Need to Know
Prototype Interface
A shared contract that every clonable object must follow. It declares one method: clone(). Any object that can be copied implements this interface.
Concrete Prototype
The actual object that carries real data and knows how to copy itself. It implements the clone() method and returns a duplicate of itself.
Client
The part of your program that asks for a copy. The client calls clone() on an existing object and receives a fresh duplicate — without knowing any details about how the object was built originally.
Structure at a Glance
«interface»
Prototype
+------------------+
| + clone(): Self |
+------------------+
▲
|
+------------------+
| ConcretePrototype|
+------------------+
| - field1 |
| - field2 |
+------------------+
| + clone(): Self | ──► returns new copy of itself
+------------------+
▲
|
Client calls .clone()
and gets a ready-to-use object
Step-by-Step: Building a Prototype in Python
Step 1 — Define the Prototype Interface
import copy
class Shape:
def clone(self):
return copy.deepcopy(self)
copy.deepcopy copies the object and everything inside it, including nested objects. A shallow copy only copies the surface — nested objects still share memory with the original.
Step 2 — Create a Concrete Prototype
class Circle(Shape):
def __init__(self, color, radius):
self.color = color
self.radius = radius
def describe(self):
print(f"Circle — Color: {self.color}, Radius: {self.radius}")
Step 3 — Clone and Customize
original = Circle("red", 10)
copy1 = original.clone()
copy2 = original.clone()
copy2.color = "blue"
original.describe() # Circle — Color: red, Radius: 10
copy1.describe() # Circle — Color: red, Radius: 10
copy2.describe() # Circle — Color: blue, Radius: 10
The original stays unchanged. Each clone lives independently.
Shallow Copy vs Deep Copy
Understanding the difference between shallow and deep copy is critical when using Prototype.
SHALLOW COPY +----------------+ +----------------+ | Object A | | Object B (copy)| | name: "Tank" | | name: "Tank" | | weapons: ──────┼──────────┼──► [sword, gun]│ +----------------+ +----------------+ Both share the SAME weapons list! Changing B's weapons changes A's too. DEEP COPY +----------------+ +----------------+ | Object A | | Object B (copy)| | name: "Tank" | | name: "Tank" | | weapons: ──────┼──►[s,g] | weapons: ──────┼──►[s,g] (separate list) +----------------+ +----------------+ Each has its OWN weapons list. Changes do NOT affect each other.
Always use deep copy when your object contains other objects inside it.
Prototype Registry: Managing Multiple Prototypes
A Prototype Registry stores pre-built template objects. The client picks one by name and clones it. This removes the need to configure objects from zero every time.
PROTOTYPE REGISTRY
+-------------------------------+
| Registry |
| "basic_enemy" → Enemy(hp:50) |
| "boss_enemy" → Enemy(hp:500)|
| "sniper" → Enemy(hp:80) |
+-------------------------------+
|
client asks: "give me a boss_enemy"
|
▼
Registry returns clone of Enemy(hp:500)
Client tweaks what it needs
Registry in Code
class EnemyRegistry:
def __init__(self):
self._templates = {}
def register(self, name, enemy):
self._templates[name] = enemy
def get(self, name):
return self._templates[name].clone()
# Setup
registry = EnemyRegistry()
registry.register("boss", Enemy(hp=500, speed=3))
registry.register("scout", Enemy(hp=80, speed=10))
# Use
boss_clone = registry.get("boss")
scout_clone = registry.get("scout")
When to Use the Prototype Pattern
Use Prototype When:
- Creating a new object involves many steps or expensive operations (database calls, file reads, complex calculations).
- You need many slightly different objects that share most settings.
- You want to avoid subclassing just to produce variations of an object.
- The type of object to create is determined at runtime, not at compile time.
Avoid Prototype When:
- Objects are simple and quick to create directly — cloning adds unnecessary complexity.
- Your objects contain circular references, which can break deep copy operations without extra handling.
Prototype vs Other Creational Patterns
+-------------------+------------------------------------+ | Pattern | How it Creates Objects | +-------------------+------------------------------------+ | Factory Method | Subclass decides what to create | | Abstract Factory | Family of related objects | | Builder | Step-by-step construction | | Singleton | Only one instance allowed | | Prototype | Clone an existing object | +-------------------+------------------------------------+
Prototype shines when the configuration cost of a new object is high. Factory patterns define creation logic in methods; Prototype carries the configuration inside the object itself.
Real Example: Document Templates in an Office App
A word processor ships with a "Monthly Report" template: specific fonts, headers, footer with company logo, and page margins. When a user clicks "New from Template," the app clones the template object — it does not rebuild all 30 settings from scratch.
"Monthly Report" Template
font: Arial 12pt
margins: 2.5cm all sides
header: company logo
footer: page number
color scheme: navy + white
|
user clicks clone
|
▼
New Document (clone)
font: Arial 12pt ← copied
margins: 2.5cm ← copied
header: company logo ← copied
footer: page number ← copied
color scheme: navy ← copied
title: "Q3 Report" ← user adds this
Advantages and Disadvantages
Advantages
- Skips complex initialization — you get a pre-built object instantly.
- Reduces subclasses — variations come from cloning and tweaking, not new classes.
- Produces independent objects — clones do not share state with the original.
Disadvantages
- Deep copying complex objects with circular references is tricky.
- Each class must implement its own
clone()method — this can clutter the codebase.
Quick Summary
PROTOTYPE PATTERN — AT A GLANCE
Problem: Creating objects from scratch is slow or complex.
Solution: Copy an existing, configured object.
Key Method: clone()
Types: Shallow copy (fast, shared references)
Deep copy (independent, safe for nested objects)
Best for: Games, document editors, UI component libraries,
configuration-heavy objects.
The Prototype pattern keeps object creation fast and flexible. Build one great object, then stamp out as many copies as you need — each ready to use and safe to modify independently.
