Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • About
  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

👥10,050visitors

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsCreational Design Patterns
✓ FreeBeginner· 8 min read

Prototype Pattern

Cloning existing objects instead of building from scratch — and the shallow-vs-deep-copy bug that catches almost everyone the first time.

Published September 22, 2026


Prototype Pattern

The idea: clone instead of construct

Some objects are expensive to build from scratch — heavy initialization, an expensive DB lookup to populate default state, or a complex object graph assembled step by step. Prototype sidesteps rebuilding all of that by cloning an existing, already-configured instance.

interface Shape extends Cloneable {
    Shape clone();
}

class Circle implements Shape {
    private int radius;
    private String color;

    Circle(int radius, String color) {
        this.radius = radius;
        this.color = color;
    }

    public Circle clone() {
        return new Circle(this.radius, this.color); // manual copy, not Object.clone()
    }
}

Circle template = new Circle(10, "red");
Circle copy1 = template.clone();
copy1.setColor("blue"); // independent — doesn't affect template

Advertisement

Shallow copy vs deep copy — where the bug hides

A naive clone only copies the object's own fields, including references — it does not clone the objects those references point to. This is fine for primitive/immutable fields, but dangerous for mutable, nested ones.

class Order implements Cloneable {
    private List<String> items;

    // SHALLOW clone — the bug
    public Order clone() {
        Order copy = new Order();
        copy.items = this.items; // same list reference!
        return copy;
    }
}

Order original = new Order();
original.items = new ArrayList<>(List.of("book"));
Order copy = original.clone();
copy.items.add("pen"); // mutates the SAME list original.items points to
// original.items now also contains "pen" — not what "clone" implies

The fix is a deep copy — recursively cloning mutable nested objects, not just copying the outer object's references:

public Order clone() {
    Order copy = new Order();
    copy.items = new ArrayList<>(this.items); // new list, same elements — safe if elements are immutable
    return copy;
}

If items held mutable objects themselves (not Strings), each element would need its own .clone() too — deep copying is recursive by nature, and how deep it needs to go depends entirely on which fields are actually mutable.

When Prototype earns its complexity

Prototype is worth it when object creation is genuinely expensive (a costly initialization step, or an object with dozens of pre-configured fields you'd otherwise have to re-specify every time) and you have a small number of "template" configurations that get cloned and lightly customized repeatedly — a common example is a graphics/game engine cloning pre-configured entity templates rather than re-running full initialization for every spawned instance.

When a plain copy constructor suffices — most everyday cases — prefer it; it's simpler, doesn't require implementing Cloneable (whose contract is famously awkward — Object.clone() is protected, doesn't call constructors, and its shallow-by-default behavior is exactly the bug shown above), and makes the deep-vs-shallow decision explicit and visible at the call site rather than hidden inside an overridden clone().

// Copy constructor — the more idiomatic modern alternative
class Order {
    private List<String> items;

    Order(Order source) { // explicit, visible copying — no Cloneable pitfalls
        this.items = new ArrayList<>(source.items);
    }
}

Copy constructors: the modern way to implement Prototype in Java

Cloneable and Object.clone() are awkward: Cloneable has no methods, clone() bypasses constructors, it's shallow by default, it doesn't work with final fields that need new values, and it throws a checked exception. Most modern Java code implements Prototype with copy constructors or copy methods instead:

public final class Order {
    private final String customerId;
    private final List<OrderLine> lines;
    private final Address shippingAddress;
    private final Map<String, String> tags;

    public Order(String customerId, List<OrderLine> lines, Address shippingAddress, Map<String, String> tags) {
        this.customerId = customerId;
        this.lines = new ArrayList<>(lines);
        this.shippingAddress = shippingAddress;
        this.tags = new HashMap<>(tags);
    }

    /** Copy constructor: every mutable part is copied deeply enough to be independent. */
    public Order(Order other) {
        this.customerId = other.customerId;                                        // immutable String: share
        this.lines = other.lines.stream().map(OrderLine::new).collect(Collectors.toCollection(ArrayList::new));
        this.shippingAddress = other.shippingAddress;                              // immutable record: share
        this.tags = new HashMap<>(other.tags);                                     // strings inside are immutable
    }

    /** Named copy-with-change methods read better than copy-then-mutate. */
    public Order withShippingAddress(Address newAddress) {
        return new Order(customerId, lines, newAddress, tags);
    }
}

The rule for deciding how deep to copy: share immutable objects (strings, records with immutable fields, LocalDate), and copy mutable ones (lists, maps, mutable entities). If every component is immutable, a copy is just a new container, which is one of the many reasons to prefer immutable designs.

Java records make this easier still: they're shallowly immutable, so "prototype + change" is simply constructing a new record from the old one's components.

A prototype registry

Prototype shines when objects are expensive or complicated to configure, and many variants start from the same few presets. Keep configured prototypes in a registry, and hand out copies:

public final class DocumentTemplates {
    private final Map<String, Document> prototypes = new ConcurrentHashMap<>();

    public void register(String key, Document configured) {
        prototypes.put(key, new Document(configured));           // store a private copy
    }

    public Document create(String key) {
        Document proto = prototypes.get(key);
        if (proto == null) throw new IllegalArgumentException("Unknown template: " + key);
        return new Document(proto);                               // callers always get an independent copy
    }
}

templates.register("invoice-gst", invoiceWithGstHeaderFootersAndStyles);
Document inv = templates.create("invoice-gst");                   // pre-styled, ready to fill in

Two copies protect the registry. One is on the way in, so the caller can't later mutate the stored prototype. The other is on the way out, so one user's edits don't leak into everyone else's documents. Forgetting either creates bugs where "every new document suddenly has yesterday's customer's name".

Real uses include:

  • Game engines spawning many enemies from a configured template.
  • Document or email templates.
  • Test fixtures ("a valid order", copied and tweaked per test).
  • Default configuration objects copied per request.
  • Spring's prototype bean scope, which is named after this pattern: each injection or lookup creates a fresh instance from the bean definition.

Testing that copies are independent

A deep-copy bug is invisible until two copies interfere in production, so test it directly:

@Test void copyIsIndependentOfOriginal() {
    Order original = sampleOrderWithTwoLines();
    Order copy = new Order(original);

    copy.lines().get(0).setQuantity(99);
    copy.tags().put("priority", "high");

    assertEquals(1, original.lines().get(0).quantity());
    assertFalse(original.tags().containsKey("priority"));
}

Mutate every mutable component of the copy, and assert that the original is unchanged. When someone later adds a new mutable field and forgets to copy it, this style of test catches it, especially if it's written generically, or kept next to the copy constructor.

Follow-up questions this topic invites — and their answers

Q: Why is Object.clone() considered a design mistake by many, including its own creators? A: It's shallow by default (silently sharing mutable state unless every subclass remembers to override correctly), it bypasses constructors entirely (so invariants enforced in a constructor aren't re-checked), and Cloneable is a marker interface with no actual clone method on it — calling clone() on a non-Cloneable object throws CloneNotSupportedException at runtime, not compile time.

Q: Is Prototype the same as the Builder pattern? A: No — Builder constructs a new object step by step from scratch (see Builder Pattern); Prototype starts from an existing fully-formed object and copies it. They can combine (clone a prototype, then use builder-style setters to adjust the copy) but solve different problems.

Q: How would you implement Prototype using serialization instead of clone()? A: Serialize the object to bytes, then deserialize into a new instance — this produces a guaranteed deep copy automatically (every reachable object in the graph gets recreated), at the cost of serialization overhead and requiring every field's type to be serializable. A reasonable fallback when the object graph is deep and hand-writing recursive clones would be error-prone.

Q: Why prefer copy constructors over clone() in Java? A: Copy constructors are ordinary, explicit code. They work with final fields, can't forget to call a constructor, throw no checked exceptions, and make the depth of each copy a visible decision. clone() is shallow by default, relies on the marker interface Cloneable, and is easy to get subtly wrong.

Q: How do you decide what to deep-copy? A: Copy anything mutable that the copy could change, or that could change underneath the copy: collections, arrays, mutable entities. Immutable values (strings, records of immutable fields, java.time types) can be shared safely.

Q: How does a prototype registry differ from a factory? A: A factory builds new objects with construction logic. A prototype registry stores fully configured example objects, and produces new ones by copying them. It's useful when configuration is data-driven, or expensive, and variants are defined at runtime rather than in code.

Advertisement

Previous

Builder Pattern

Next

Adapter & Facade

AI Tutor

Lesson: Prototype Pattern

Quick actions

AI responses can be inaccurate. Verify critical information.