Design Pattern

Prototype Pattern

Clean Java-only production-ready implementation.


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.

// ─── 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);
    }
}