Home/Learn/Low Level Design/Prototype Pattern

Prototype Pattern

Intermediate
Creational Patterns

Creates new objects by copying (cloning) an existing instance, avoiding the cost of creating objects from scratch.

Overview

The Prototype pattern is used when object creation is expensive (e.g. loading configuration from DB) and you need many similar instances. Instead of calling new, you clone an existing "prototype" object. Java provides the Cloneable marker interface and Object.clone(), but it is widely considered broken — it creates a shallow copy, skips constructors, and requires catching CloneNotSupportedException. Production code uses copy constructors or static factory copy methods. Deep copy vs shallow copy is the central interview focus: shallow copy shares mutable references, causing aliasing bugs.

Shallow Copy vs Deep Copy

A shallow copy duplicates the top-level object but shares references to nested mutable objects. Modifying a nested object in the copy affects the original. A deep copy recursively clones all referenced objects, producing fully independent instances.

Java — Shallow clone vs deep clone comparison
import java.util.ArrayList;
import java.util.List;

public class UserProfile implements Cloneable {
    private String name;
    private List<String> skills;  // mutable reference — clone danger

    public UserProfile(String name, List<String> skills) {
        this.name   = name;
        this.skills = skills;
    }

    // Shallow clone — skills list is SHARED
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // copies reference to skills, not the list itself
    }

    // Deep clone — skills list is INDEPENDENT
    public UserProfile deepClone() {
        return new UserProfile(this.name, new ArrayList<>(this.skills));
    }

    public List<String> getSkills() { return skills; }
    public String getName()         { return name; }
}

// Demonstrating the difference
UserProfile original = new UserProfile("Alice", new ArrayList<>(List.of("Java", "LLD")));

// Shallow clone
try {
    UserProfile shallow = (UserProfile) original.clone();
    shallow.getSkills().add("Python"); // modifies original.skills too!
    System.out.println(original.getSkills()); // [Java, LLD, Python] — aliased!
} catch (CloneNotSupportedException e) { e.printStackTrace(); }

// Deep clone
UserProfile deep = original.deepClone();
deep.getSkills().add("Python");         // original is unaffected
System.out.println(original.getSkills()); // [Java, LLD] — independent

Prototype Registry

A Prototype Registry stores pre-built prototypes keyed by type and returns clones on demand. This is useful when prototype creation is expensive (e.g. loading from config, DB, or XML) and you want caching with fresh copies on each use.

Java — Prototype Registry with copy constructor
// Prototype interface
public interface Prototype<T> {
    T clone();
}

// Complex object whose construction is expensive
public class ReportTemplate implements Prototype<ReportTemplate> {
    private final String templateName;
    private final List<String> columns;
    private final Map<String, String> styles;

    // Expensive constructor (simulated)
    public ReportTemplate(String templateName) {
        this.templateName = templateName;
        this.columns = new ArrayList<>(loadColumnsFromDb(templateName)); // expensive!
        this.styles  = new HashMap<>(loadStylesFromConfig(templateName));
    }

    // Private copy constructor for cloning
    private ReportTemplate(ReportTemplate source) {
        this.templateName = source.templateName;
        this.columns      = new ArrayList<>(source.columns);
        this.styles       = new HashMap<>(source.styles);
    }

    @Override
    public ReportTemplate clone() {
        return new ReportTemplate(this); // fast deep copy via copy constructor
    }

    private List<String> loadColumnsFromDb(String name) {
        System.out.println("Loading from DB (expensive)...");
        return List.of("id", "name", "date");
    }
    private Map<String, String> loadStylesFromConfig(String name) {
        return Map.of("font", "Arial", "size", "12");
    }

    public String getTemplateName() { return templateName; }
}

// Registry
public class PrototypeRegistry {
    private final Map<String, ReportTemplate> registry = new HashMap<>();

    public void register(String key, ReportTemplate template) {
        registry.put(key, template);
    }

    public ReportTemplate get(String key) {
        ReportTemplate t = registry.get(key);
        if (t == null) throw new IllegalArgumentException("Unknown template: " + key);
        return t.clone(); // always return a fresh clone
    }
}

// Usage
PrototypeRegistry registry = new PrototypeRegistry();
registry.register("sales", new ReportTemplate("sales")); // expensive — done once

ReportTemplate r1 = registry.get("sales"); // fast clone
ReportTemplate r2 = registry.get("sales"); // another fast clone — independent

Key Points to Remember

  • 1Prefer copy constructors or static factory copy methods over Cloneable — it is broken by design.
  • 2Shallow copy shares mutable references; deep copy creates fully independent object graphs.
  • 3Prototype Registry caches expensive prototypes and returns clones — combines Prototype + Flyweight.
  • 4Use serialization (serialize + deserialize) for generic deep cloning when copy constructors are impractical.
  • 5Java record types are immutable value objects — cloning is unnecessary for records.

Interview Questions

Sign in to ask Aria
1

What is the difference between shallow copy and deep copy? Give a code example.

MediumAmazon
2

Why is Cloneable considered broken in Java?

HardGoogle
3

How would you implement a deep clone without Cloneable?

MediumMicrosoft
4

When would you use the Prototype pattern over the Factory Method pattern?

MediumUber

Ask Aria about Prototype Pattern

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…