Design Pattern

Prototype Pattern

Clean Java-only production-ready implementation.


What Problem It Solves

Creating a copy of an object is expensive (DB query, network call) or complex (deep graph of nested objects). Instead of re-creating from scratch, clone an existing instance and modify what's different.

Shallow vs Deep Copy

AspectShallowDeep
CopiesReferences onlyCreates new independent objects
RiskMutations affect both original and cloneSafe โ€” independent
PerformanceFastSlower for deep graphs
Use whenImmutable children, or read-only shared stateFull isolation needed

Where Prototype Appears in LLD

  • Cache (#31): Clone a cached response instead of re-fetching
  • Document Editor (not in problems, but common): Duplicate shapes/objects
  • Config (#15): Clone default config, modify specific values

Implementation

// โ”€โ”€โ”€ EXAMPLE 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// WHAT WE ARE IMPLEMENTING:
// A user authorization registry copying pre-configured permission templates
// (Admin, Guest).
//
// WHERE THE PATTERN FITS IN:
// UserPrototype is the Prototype interface declaring clone(). AdminPrototype
// and GuestPrototype are Concrete Prototypes cloned dynamically.
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// --- Prototype interface ---
interface ClonableDocument<T> {
    T clone();
}

// --- Concrete prototype ---
class ReportDocument implements ClonableDocument<ReportDocument> {
    private final String title;
    private final String author;
    private final java.util.List<String> sections;
    private final java.util.Map<String, Object> metadata;

    public ReportDocument(String title, String author) {
        this.title = title;
        this.author = author;
        this.sections = new java.util.ArrayList<>();
        this.metadata = new java.util.HashMap<>();
        // Simulated expensive load
        loadFromDatabase();
    }

    private void loadFromDatabase() {
        System.out.println("  [DB] Loading report template...");
        sections.add("Executive Summary");
        sections.add("Findings");
        sections.add("Recommendations");
        metadata.put("template", "annual");
        metadata.put("version", "v2");
    }

    // Private copy constructor โ€” the actual prototype mechanism
    private ReportDocument(ReportDocument source) {
        this.title = source.title;
        this.author = source.author;
        this.sections = new java.util.ArrayList<>(source.sections);  // Deep copy
        this.metadata = new java.util.HashMap<>(source.metadata);
    }

    public ReportDocument clone() {
        System.out.println("  [Clone] Creating copy (no DB load)");
        return new ReportDocument(this);
    }

    public void setTitle(String title) { this.title = title; }

    @Override
    public String toString() {
        return "Report{title='" + title + "', author='" + author +
               "', sections=" + sections + "}";
    }
}

public class Main {
    public static void main(String[] args) {
        // Expensive creation โ€” happens once
        ReportDocument template = new ReportDocument("Annual Report", "Default");

        // Cheap clones โ€” customize each
        ReportDocument report1 = template.clone();
        report1.setTitle("2024 Annual Report");

        ReportDocument report2 = template.clone();
        report2.setTitle("2025 Annual Report");

        System.out.println(report1);
        System.out.println(report2);
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...