Overview
The Prototype pattern creates new objects by copying an existing instance (the prototype) instead of constructing from scratch. It is useful when construction is expensive (loading templates, parsing configs) or when you want many similar objects that differ slightly, such as document templates or game units.
The core decision is shallow vs deep copy. A shallow copy shares nested objects with the original, so changing a nested list affects both. A deep copy duplicates the whole graph. A prototype registry stores named prototypes that clients clone and customize.
Instead of designing a new form each time, you fill in a master template and photocopy it. Each copy can then be filled in differently.
When to use it
- Object creation is costly but copying is cheap.
- Many objects start from a few preset configurations.
- You need copies without knowing concrete classes.
Where it shows up in interviews
Recognize it when: create objects from saved templates.
- Design a document editor with templates
- Design a game with unit presets
Recognize it when: copy state before changes.
- Design a drawing app with undo
- Design a spreadsheet
Where it is used in real software
Object.create and structuredClone copy objects; the language itself is prototype-based.
Beans with prototype scope are created fresh per request from a definition.
Figma components and duplicate commands clone objects with overrides.
Key terms
- Prototype
- An instance used as a template for copies.
- clone / copy
- Method that returns a copy of the object.
- Shallow copy
- Copies top-level fields; nested objects are shared.
- Deep copy
- Recursively copies nested objects.
- Prototype registry
- Named collection of prototypes.
How it works, step by step
- 1Define a copy method
In an interface: copy(): T.
- 2Implement it per class
Decide shallow vs deep per field.
- 3Create prototypes
Preconfigured instances.
- 4Register them
Map name to prototype.
- 5Clone and customize
registry.get('invoice').copy().withCustomer(c).
Shallow vs deep copy
original = { title: 'Report', tags: ['q1'] }
| Copy type | copy.tags.push('draft') | original.tags |
|---|---|---|
| Shallow ({...original}) | ['q1', 'draft'] | ['q1', 'draft'] (shared!) |
| Deep (structuredClone) | ['q1', 'draft'] | ['q1'] (independent) |
NOWCopy type: Shallow ({...original}) | copy.tags.push('draft'): ['q1', 'draft'] | original.tags: ['q1', 'draft'] (shared!)
Shallow copies are fast but share nested state; choose deliberately per field.
Implementation
interface Prototype<T> { copy(): T } class DocumentTemplate implements Prototype<DocumentTemplate> { constructor( public title: string, public sections: string[], public styles: { font: string; size: number }, ) {} copy(): DocumentTemplate { return new DocumentTemplate(this.title, [...this.sections], { ...this.styles }); // deep enough }} class TemplateRegistry { private templates = new Map<string, DocumentTemplate>(); register(name: string, t: DocumentTemplate) { this.templates.set(name, t); } create(name: string) { const t = this.templates.get(name); if (!t) throw new Error(`Unknown template ${name}`); return t.copy(); }} const registry = new TemplateRegistry();registry.register("invoice", new DocumentTemplate("Invoice", ["Header", "Items", "Total"], { font: "Inter", size: 11 }));const doc = registry.create("invoice");doc.sections.push("Notes"); // prototype unaffectedComplexity and performance
Fast.
Can be expensive.
Trade-offs
Deep copying graphs with cycles or external resources (connections) is tricky.
If construction is cheap and simple, a factory is clearer than cloning.
Variants and related techniques
new Enemy(other); preferred over Java's Cloneable.
withX() methods return modified copies (records, persistent data).
Common mistakes
- Using Java's Cloneable and Object.clone().
Fix: It is shallow and awkward; prefer copy constructors or copy methods.
- Accidentally sharing mutable nested state.
Fix: Copy collections and mutable children.
Interview questions
Shallow vs deep copy?
A shallow copy duplicates top-level fields but shares nested objects; a deep copy also duplicates nested objects so the copy is fully independent.
When is Prototype useful?
When creating objects is expensive or configuration-heavy and many similar instances are needed, such as templates, game units, or presets.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| Template registry for emails | Easy | Clone and customize. |
| Deep copy a shape group with nested shapes | Medium | Recursive copy. |