Creational

Prototype Pattern

Clone existing objects instead of constructing from scratch. An intermediate creational pattern — the answer when building an object is expensive but copying one is cheap.

Overview ยท Creational ยท Singleton ยท Factory Method ยท Abstract Factory ยท Builder ยท Prototype ยท Adapter ยท Bridge ยท Composite ยท Decorator ยท Facade ยท Flyweight ยท Proxy ยท Observer ยท Strategy ยท Command ยท Template Method ยท Chain of Resp. ยท State ยท Mediator ยท Iterator ยท Visitor ยท Memento ยท Interpreter
Category: Creational Difficulty: Intermediate Interview: Tier 3 Confused with: Builder
01
Section One ยท The Problem

Why Prototype Exists

You are building a game engine. Each level has hundreds of enemies — orcs, goblins, dragons — each configured with health, speed, attack power, equipped weapons, spawn position, AI behaviour tree, and a sprite sheet loaded from disk. Creating one enemy is expensive: parse the config file, load the sprite from disk, compile the shader, build the AI tree. Now multiply that by 200 enemies per level. The naive approach constructs each enemy from scratch, repeating the same expensive setup for every orc that shares 95% of its configuration with every other orc.

Naive approach — constructing every enemy from scratch
// โœ— Every orc is built from scratch โ€” same expensive setup repeated 50 times for (int i = 0; i < 50; i++) { Enemy orc = new Enemy(); orc.loadSprite("orc.png"); // disk I/O ร— 50 orc.compileShader("orc_shader.glsl"); // GPU compile ร— 50 orc.buildAITree("aggressive"); // parse + build ร— 50 orc.setHealth(100); orc.setSpeed(5); orc.setAttack(15); orc.setPosition(randomSpawn()); // only this differs enemies.add(orc); } // 50 orcs ร— 3 expensive operations = 150 redundant operations

What goes wrong:

  • Repeated expensive setup — disk I/O, GPU compilation, and AI tree parsing happen 50 times for identical orcs; only spawn position differs
  • Tight coupling to concrete classes — the spawning code must know every constructor argument and initialization step for every enemy type
  • Can’t create objects at runtime from unknown types — if a level editor adds a new enemy type via config, the code can’t new a class it doesn’t know at compile time
  • Scattered initialization logic — the 7-step setup is duplicated everywhere enemies are created; changing orc health means editing every spawn site
Without Prototype — expensive construction repeated for every instance
new Enemy() loadSprite() compileShader() buildAITree() × 50 = 150 redundant disk/GPU/parse operations for 50 nearly-identical orcs ✗ Same sprite, same shader, same AI tree loaded 50 times ✗ Spawning code must know every constructor detail for every type ✗ New enemy types from config? Can’t new a class you don’t know

This is the problem Prototype solves — build one fully-configured “master copy” of each enemy type, then clone it whenever you need a new instance. The clone copies the already-loaded sprite, already-compiled shader, and already-built AI tree in memory — no disk I/O, no GPU compilation, no parsing. Tweak only what differs (spawn position), and you have a new enemy in microseconds instead of milliseconds.

02
Section Two ยท The Pattern

What Is Prototype?

Prototype is a creational pattern that creates new objects by cloning an existing instance (the prototype) instead of constructing from scratch. Each prototype knows how to copy itself. The client asks the prototype “give me a copy of yourself,” receives an independent clone, and tweaks only what’s different. The client never needs to know the concrete class, the constructor arguments, or the initialization sequence — it just calls clone().

GoF Intent: “Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.”
— Gamma, Helm, Johnson, Vlissides (1994)
Analogy — cell division: When your body needs a new cell, it doesn’t build one from raw atoms. It takes an existing cell (the prototype) and divides it — copying the DNA, the organelles, the membrane. The new cell is an independent copy that can then specialise (differentiate). This is dramatically faster than assembling a cell from scratch. In the same way, Prototype clones an existing, fully-configured object and lets you tweak the copy. The original stays untouched and ready for the next clone.

Key insight: Prototype shifts the creation question from “which class should I instantiate?” to “which instance should I copy?” This is fundamentally different from Factory Method (which decides the class) or Builder (which assembles step by step). Prototype doesn’t care about classes or construction steps — it only needs a live, configured object and a way to duplicate it. This makes it uniquely powerful for dynamic systems where object types are defined at runtime (game editors, visual builders, document templates).

Each prototype implements a clone() method that copies its own state
Cloning is a memory-only operation — no disk I/O, no parsing, no constructor ceremony
Client calls prototype.clone() instead of new ConcreteClass(...)
Client is decoupled from the concrete class — it only knows the prototype interface
A prototype registry stores named prototypes: "orc" → master orc, "dragon" → master dragon
New types can be added at runtime by registering a new prototype — no code changes, no recompilation
After cloning, the client tweaks only what differs (e.g. spawn position)
95% of the object is reused from the prototype; 5% is customised — fast and consistent
03
Section Three ยท Anatomy

Participants & Structure

Participant Role In the Analogy
Prototype An interface (or abstract class) that declares a clone() method. Every cloneable object must implement this contract. The concept of “a cell that can divide itself.”
Concrete Prototype Implements clone() by copying its own fields into a new instance. Handles deep-copy logic for mutable internal state (lists, maps, nested objects). A specific cell type (red blood cell, neuron) that knows how to replicate its own organelles.
Prototype Registry (optional) A map of String → Prototype that stores pre-configured master copies. The client looks up a prototype by name and clones it. New types can be registered at runtime. A stem-cell bank — labelled vials of master cells ready to be cloned on demand.
Client Asks the registry (or a prototype directly) for a clone. Receives an independent copy and customises only what differs. Never calls new ConcreteClass(). The body — requests “give me another red blood cell” without knowing how to build one from scratch.
Prototype — UML Class Diagram
«interface» Prototype + clone() : Prototype OrcPrototype - health, speed, sprite + clone() : Prototype DragonPrototype - health, speed, breath + clone() : Prototype GoblinPrototype - health, speed, stealth + clone() : Prototype PrototypeRegistry Map<String, Prototype> + get(key).clone() stores Spawner (Client) looks up & clones ■ Blue = interface ■ Green = concrete ■ Gold = registry ■ Dark = client
Deep clone vs. shallow clone:
  • A shallow clone copies field values directly — if a field is a reference (e.g. a List), both the original and clone share the same list object.
  • Mutating one corrupts the other.
  • A deep clone recursively copies all mutable internal objects so the clone is fully independent.
  • Always deep-clone mutable fields in your clone() implementation.
04
Section Four ยท How It Works

The Pattern In Motion

Scenario: A game level spawner that needs 50 orcs. Instead of constructing each from scratch, it clones a pre-built master orc and tweaks the spawn position.

Step 1 — Build the master prototype once: load sprite, compile shader, build AI tree, set base stats
This expensive setup happens exactly once. The master orc is fully configured and stored in the registry under key "orc".
Step 2 — Register prototypes: registry.put("orc", masterOrc), registry.put("dragon", masterDragon)
The registry is a Map<String, Prototype>. New types can be added at runtime — a level editor can register a custom enemy without recompiling.
Step 3 — Spawner calls registry.get("orc").clone()
The master orc’s clone() creates a new OrcPrototype with all fields copied (deep clone for mutable state). No disk I/O, no GPU work — pure memory copy.
Step 4 — Spawner customises the clone: clone.setPosition(randomSpawn())
Only the spawn position differs. Health, speed, sprite, shader, AI tree — all inherited from the prototype. The clone is independent; changing it doesn’t affect the master.
Step 5 — Repeat 49 more times
50 orcs created in microseconds. The expensive setup ran once; cloning ran 50 times at memory speed. Adding a goblin wave: registry.get("goblin").clone() — same pattern, different key.
Before / After — construct from scratch vs. clone from prototype
BEFORE — construct from scratch new Orc() disk I/O GPU AI parse × 50 ✗ 150 expensive ops ✗ Slow, redundant AFTER — clone from prototype Master Orc built once .clone() Orc #1 Orc #2 ... #50 setPosition(randomSpawn()) ✔ 1 expensive build + 50 memory copies ✔ Microseconds, not milliseconds
The pattern in pseudocode
// โ”€โ”€ Build master prototypes once (expensive) โ”€โ”€ Prototype masterOrc = new OrcPrototype(100, 5, "orc.png", "aggressive"); Prototype masterDragon = new DragonPrototype(500, 3, "dragon.png", "fire"); // โ”€โ”€ Register in prototype map โ”€โ”€ registry.put("orc", masterOrc); registry.put("dragon", masterDragon); // โ”€โ”€ Spawn 50 orcs by cloning (cheap) โ”€โ”€ for (int i = 0; i < 50; i++) { Enemy orc = (Enemy) registry.get("orc").clone(); // memory copy, no disk I/O orc.setPosition(randomSpawn()); // tweak what differs enemies.add(orc); }
Prototype vs. copy constructor:
  • Java’s new ArrayList<>(existingList) is a copy constructor — it works, but the caller must know the concrete class.
  • Prototype is polymorphic: the client calls clone() on the interface and gets the right concrete type without knowing it.
  • This is critical when types are determined at runtime.
05
Section Five ยท Java Stdlib

You Already Use This

Prototype is baked into the Java language itself via java.lang.Cloneable and Object.clone(). While the JDK’s cloning mechanism has well-known design flaws, the pattern appears throughout the standard library.

IN JAVA
Example 1 java.lang.Object.clone() — the native prototype mechanism. Any class implementing Cloneable can override clone() to produce a field-by-field copy. Object.clone() performs a shallow copy by default — you must override it for deep cloning of mutable fields.
Example 2 java.util.ArrayList copy constructor — new ArrayList<>(source) creates a shallow clone of the list. The new list is independent (adding/removing elements doesn’t affect the original), but the elements themselves are shared references. This is prototype-style creation: copy an existing collection rather than building one from scratch.
Example 3 java.util.Date โ€” implements Cloneable. Defensive copying in the JDK often uses (Date) date.clone() to prevent callers from mutating internal state. This is Prototype used for safe snapshot creation.
Stdlib usage — Object.clone()
// Cloneable + clone() โ€” Java's built-in prototype mechanism class GameConfig implements Cloneable { private String level; private List<String> powerups; @Override public GameConfig clone() { try { GameConfig copy = (GameConfig) super.clone(); // shallow copy copy.powerups = new ArrayList<>(this.powerups); // deep copy mutable field return copy; } catch (CloneNotSupportedException e) { throw new AssertionError(); // can't happen โ€” we implement Cloneable } } } // Usage โ€” clone existing config and tweak GameConfig base = new GameConfig("forest", List.of("shield", "speed")); GameConfig variant = base.clone(); variant.setLevel("desert"); // independent copy โ€” base is unchanged
Why Cloneable is considered broken:
  • Josh Bloch (Effective Java) calls Cloneable a “broken” interface — it has no methods, clone() is on Object, and it returns Object requiring a cast.
  • Modern Java code often prefers a copy constructor or a static factory like Enemy.from(existingEnemy) instead of Cloneable.
  • The pattern is the same — clone an existing instance — but the mechanism is cleaner.
06
Section Six ยท Implementation

Build It Once

Domain: Game Character Cloning. A Prototype interface with clone(), two concrete prototypes (Warrior, Mage), a PrototypeRegistry, and a spawner that clones from the registry.

Java — Prototype Pattern Game Characters (core)
// โ”€โ”€ Prototype interface โ”€โ”€ interface GameCharacter { GameCharacter clone(); void setPosition(int x, int y); String describe(); } // โ”€โ”€ Concrete Prototype: Warrior โ”€โ”€ class Warrior implements GameCharacter { private int hp, attack; private String weapon; private List<String> skills; private int x, y; // Deep clone โ€” copies mutable List public GameCharacter clone() { Warrior copy = new Warrior(this.hp, this.attack, this.weapon); copy.skills = new ArrayList<>(this.skills); // deep copy return copy; } }
Private no-arg constructor for clones:
  • Notice how Warrior has a private no-arg constructor used only by clone().
  • The public constructor does expensive init (sprite loading, shader compilation).
  • The private one skips it — clones get a cheap path. This is the key performance trick of Prototype.
07
Section Seven ยท Watch Out

Common Mistakes

Mistake #1 — Shallow clone of mutable fields: This is the most dangerous Prototype bug. If clone() copies a List reference instead of creating a new list, the clone and the original share the same list. Adding a skill to the clone adds it to the master — corrupting every future clone. Always deep-copy mutable fields: copy.skills = new ArrayList<>(this.skills).
✗ Wrong — shallow copy of mutable list
// โœ— Both original and clone share the SAME list object public GameCharacter clone() { Warrior copy = new Warrior(); copy.skills = this.skills; // โ† SHARED reference โ€” mutation leaks! return copy; }
✔ Correct — deep copy of mutable list
// โœ“ Clone gets its own independent list public GameCharacter clone() { Warrior copy = new Warrior(); copy.skills = new ArrayList<>(this.skills); // โ† independent copy return copy; }
Mistake #2 — Running expensive init during clone:
  • If clone() uses the same constructor as the public factory path, the clone pays the full initialization cost (disk I/O, GPU work).
  • Use a private no-arg constructor that skips expensive setup.
  • Clones copy already-loaded resources from the prototype — they should never reload them.
Mistake #3 — Forgetting to clone nested objects:
  • Deep cloning isn’t just one level deep.
  • If your List<Weapon> contains mutable Weapon objects, copying the list isn’t enough — you must also clone each Weapon inside it.
  • Otherwise, the clone and the original share the same Weapon instances.
  • Rule: recursively clone every mutable object in the graph.
Mistake #4 — Using Prototype when objects are cheap to construct:
  • If creating an object takes microseconds (no I/O, no parsing, no complex setup), cloning adds unnecessary complexity.
  • Prototype shines when construction is genuinely expensive — disk I/O, network calls, GPU compilation, deep object graphs.
  • For simple POJOs, just use new.
08
Section Eight ยท Decision Guide

When To Use Prototype

Use Prototype When
  • Object construction is expensive — disk I/O, network calls, GPU work, deep object graphs — but copying is cheap
  • You need many similar instances that differ in only a few fields — clone the master and tweak
  • Object types are determined at runtime — loaded from config, created in a visual editor, defined by users — and you can’t hardcode new calls
  • You want to decouple the client from concrete classes — the client knows only the Prototype interface
  • You need a snapshot/undo mechanism — clone the current state to save it, restore by cloning the saved copy
Avoid Prototype When
  • Objects are cheap to construct — simple POJOs with no I/O or complex setup; new is simpler
  • Objects have deeply nested mutable graphs that make clone() error-prone and hard to maintain
  • You need to decide which class to instantiate at runtime — use Factory Method instead
  • You need to create families of products — use Abstract Factory instead
Prototype vs. Confused Patterns
Pattern Creates by Focus When to pick it
Prototype ← this Cloning an existing instance Copy instead of construct Construction is expensive; copying is cheap
Factory Method Subclass overriding a method Which class to instantiate Decision on type is at compile time via inheritance
Abstract Factory Factory interface for families Which family of products Products must come from the same family
Builder Step-by-step fluent API How to assemble one complex object Many optional fields, validation needed
Decision Flowchart
Need to create a new object? Yes Is construction expensive? No Use new / Factory Yes Have a configured instance to copy? No Use Builder Yes Prototype
09
Section Nine ยท Practice

Problems To Solve

Prototype problems test whether you can implement deep cloning correctly, use a registry for runtime type discovery, and avoid the shallow-copy trap.

Difficulty Problem Key Insight
Easy Document Template Cloner
Build a Document prototype with title, body text, and a list of tags. The user selects a template (e.g. “Invoice”, “Report”), clones it, and fills in the details. Verify that changing the clone’s tags list doesn’t affect the template.
Tests the basic clone + deep-copy of a mutable list. The registry holds 2–3 templates. The trap: shallow-copying the tags list means all clones share the same list.
Medium Shape Editor with Undo
Build a drawing app with Circle, Rectangle, and Line shapes. Each shape has position, colour, and stroke. Implement “duplicate shape” (clone + offset) and “undo” (clone state before each edit, push to undo stack). All shapes share a Shape interface with clone().
Tests polymorphic cloning (client clones Shape without knowing the concrete type) and using Prototype for undo snapshots. The tricky part: clone() must return the correct concrete type.
Medium Config-Driven Enemy Spawner
Enemy types are defined in a JSON config file (not in code). At startup, parse each entry into a prototype and register it. The spawner clones from the registry by key. Add a new enemy type by editing the config — no recompilation.
Tests the runtime type discovery power of Prototype. The registry is populated dynamically; the spawner never names a concrete class. This is impossible with Factory Method alone — you’d need to edit the factory for each new type.
Hard Deep Graph Cloning
Build a Company object containing Department objects, each containing Employee objects. Employees have mutable Address objects. Implement clone() that deep-copies the entire graph. Prove independence: mutating a cloned employee’s address must not affect the original company.
Tests recursive deep cloning of a 4-level object graph. Every mutable object at every level must be cloned. The test: clone.getDept(0).getEmployee(0).getAddress().setCity("X") must not change the original. This is where Prototype gets hard — and where serialization-based cloning (serialize โ†’ deserialize) becomes an alternative.
Interview Tip:
  • When asked about Prototype, the interviewer wants to see: (1) a clone() method on the Prototype interface that returns the Prototype type; (2) deep-copy logic for all mutable fields (not just super.clone()); (3) a registry for runtime type lookup; (4) a clear explanation of when to use it (expensive construction) vs.
  • when not to (simple objects).
  • Bonus: mention that Java’s Cloneable is broken and modern code prefers copy constructors or static factory methods.