Back to All Design Patterns
Pattern 15 of 22
Creational PatternINTERMEDIATE6 min deep dive
Prototype Pattern Pattern
Specifies the kinds of objects to create using a prototypical instance, and creates new objects by copying this prototype.
Real-World Mental Model / Metaphor:
Cell division (mitosis). A biological cell duplicates its DNA and splits into an identical copy, without having to rebuild the cell from raw atoms from scratch.
Interactive Runtime Simulator
Test and tweak inputs dynamicallyInteractive Prototype Pattern SimulatorLIVE PLAYGROUND
Interact with the controls below to see how this design pattern executes in memory at runtime.
Switch Target Factory Platform:
The client code only interacts with
GUIFactory.createButton() and GUIFactory.createCheckbox(). It never couples directly to concrete classes!CONCRETE PRODUCTS CREATEDmac
Rendered Button:Rendered Checkbox:
The Problem It Solves
Directly instantiating and copying complex objects whose private fields cannot be accessed from outside, or when object initialization involves expensive database queries or file loading.
The Architectural Solution
Declare a Cloneable / Prototype interface with a clone() method. The object itself copies its own private fields into a new instance.
Pattern Structure & Participants
| Participant | Role & Responsibility | Type |
|---|---|---|
| Prototype (Interface) | Declares clone() | interface |
| ConcretePrototype | Implements deep/shallow copy of fields | class |
| PrototypeRegistry | Stores pre-warmed prototypes by key | class |
Collaboration Rules:
- Client requests registry.get('warrior').clone()
- Clone method returns an independent copy ready for customization
Production Code Implementation
Prototype Pattern.java
public interface Prototype<T> {
T cloneObject();
}
public class GameNPC implements Prototype<GameNPC> {
private String model3D; // Expensive 50MB 3D mesh
private int health;
private List<String> inventory;
public GameNPC(String model3D, int health, List<String> inventory) {
this.model3D = model3D;
this.health = health;
this.inventory = new ArrayList<>(inventory);
}
@Override
public GameNPC cloneObject() {
// Deep copy of mutable collections
return new GameNPC(this.model3D, this.health, new ArrayList<>(this.inventory));
}
} When to Use:
- •When your code shouldn't depend on the concrete classes of objects that you need to copy.
- •When you want to reduce the number of subclasses that only differ in the way they initialize their respective objects.
When to Avoid (Anti-Pattern):
- •When cloning complex objects that have circular references (can lead to infinite recursion during deep copy).
Staff Engineering Interview Insights & Gotchas
- Explain the critical difference between Shallow Copy (references shared) vs Deep Copy (nested objects cloned).