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