The Prototype pattern creates new objects by cloning an existing instance rather than building one from scratch. When object creation is expensive — involving database queries, file I/O, or complex initialization — copying a pre-configured prototype is significantly faster. This pattern gives you a way to produce new instances with a known-good starting state.
Imagine a document management system where users create reports from templates. Each template has a predefined layout, styling, headers, footers, and metadata. Constructing a new document from scratch every time means repeating the same expensive setup — loading fonts, parsing layout rules, and applying styling. Worse, if users frequently create variations of the same template, you are doing redundant work over and over.
The Prototype pattern maintains a registry of pre-built template objects. When a user needs a new document, the system clones the appropriate prototype and lets the user customize only what is different. The clone operation copies the full internal state, so the new document starts fully configured and ready for editing — without repeating the original setup cost.
Create by copying, not constructing. The prototype encapsulates the knowledge of how to replicate itself, so clients never need to know the details of initialization. This is especially powerful when the class hierarchy is complex or the exact type is determined at runtime.
This example implements a document template system where reports are cloned from pre-built prototypes.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// Prototype interface
public interface DocumentPrototype {
DocumentPrototype cloneDocument();
}
// Concrete prototype
public class ReportDocument implements DocumentPrototype {
private String title;
private String templateType;
private List<String> sections;
private Map<String, String> metadata;
private String headerText;
private String footerText;
private String fontFamily;
private int fontSize;
public ReportDocument() {
this.sections = new ArrayList<>();
this.metadata = new HashMap<>();
}
// Deep copy constructor
private ReportDocument(ReportDocument source) {
this.title = source.title;
this.templateType = source.templateType;
this.sections = new ArrayList<>(source.sections);
this.metadata = new HashMap<>(source.metadata);
this.headerText = source.headerText;
this.footerText = source.footerText;
this.fontFamily = source.fontFamily;
this.fontSize = source.fontSize;
}
@Override
public DocumentPrototype cloneDocument() {
return new ReportDocument(this);
}
// Setters for configuration
public void setTitle(String title) { this.title = title; }
public void setTemplateType(String type) { this.templateType = type; }
public void addSection(String section) { this.sections.add(section); }
public void setMetadata(String key, String value) { this.metadata.put(key, value); }
public void setHeaderText(String text) { this.headerText = text; }
public void setFooterText(String text) { this.footerText = text; }
public void setFont(String family, int size) {
this.fontFamily = family;
this.fontSize = size;
}
@Override
public String toString() {
return "ReportDocument{" +
"title='" + title + "'" +
", type='" + templateType + "'" +
", sections=" + sections.size() +
", font=" + fontFamily + " " + fontSize + "pt" +
"}";
}
}
// Template registry
public class DocumentTemplateRegistry {
private final Map<String, DocumentPrototype> templates = new HashMap<>();
public void registerTemplate(String name, DocumentPrototype prototype) {
templates.put(name, prototype);
}
public DocumentPrototype createFromTemplate(String name) {
DocumentPrototype prototype = templates.get(name);
if (prototype == null) {
throw new IllegalArgumentException("Unknown template: " + name);
}
return prototype.cloneDocument();
}
}
// Usage
public class Application {
public static void main(String[] args) {
// Build expensive prototypes once
ReportDocument financialTemplate = new ReportDocument();
financialTemplate.setTitle("Quarterly Financial Report");
financialTemplate.setTemplateType("financial");
financialTemplate.setFont("Arial", 11);
financialTemplate.setHeaderText("CONFIDENTIAL - Financial Report");
financialTemplate.setFooterText("Generated by Report System v2.0");
financialTemplate.addSection("Executive Summary");
financialTemplate.addSection("Revenue Analysis");
financialTemplate.addSection("Expense Breakdown");
financialTemplate.addSection("Projections");
financialTemplate.setMetadata("department", "Finance");
financialTemplate.setMetadata("classification", "confidential");
ReportDocument techTemplate = new ReportDocument();
techTemplate.setTitle("Technical Review");
techTemplate.setTemplateType("technical");
techTemplate.setFont("Courier New", 10);
techTemplate.setHeaderText("Engineering - Technical Review");
techTemplate.setFooterText("Internal Use Only");
techTemplate.addSection("Architecture Overview");
techTemplate.addSection("Performance Metrics");
techTemplate.addSection("Risk Assessment");
techTemplate.setMetadata("department", "Engineering");
// Register prototypes
DocumentTemplateRegistry registry = new DocumentTemplateRegistry();
registry.registerTemplate("financial", financialTemplate);
registry.registerTemplate("technical", techTemplate);
// Clone and customize
ReportDocument q1Report = (ReportDocument) registry.createFromTemplate("financial");
q1Report.setTitle("Q1 2025 Financial Report");
System.out.println(q1Report);
ReportDocument q2Report = (ReportDocument) registry.createFromTemplate("financial");
q2Report.setTitle("Q2 2025 Financial Report");
System.out.println(q2Report);
ReportDocument apiReview = (ReportDocument) registry.createFromTemplate("technical");
apiReview.setTitle("API Gateway Technical Review");
System.out.println(apiReview);
}
}
The same document template system in Python, using the copy module for deep cloning.
import copy
from typing import Optional
class ReportDocument:
def __init__(self):
self.title: str = ""
self.template_type: str = ""
self.sections: list[str] = []
self.metadata: dict[str, str] = {}
self.header_text: str = ""
self.footer_text: str = ""
self.font_family: str = "Arial"
self.font_size: int = 12
def clone(self) -> "ReportDocument":
"""Deep copy this document to create an independent clone."""
return copy.deepcopy(self)
def __str__(self):
return (
f"ReportDocument(title='{self.title}'"
f", type='{self.template_type}'"
f", sections={len(self.sections)}"
f", font={self.font_family} {self.font_size}pt)"
)
class DocumentTemplateRegistry:
def __init__(self):
self._templates: dict[str, ReportDocument] = {}
def register(self, name: str, prototype: ReportDocument):
self._templates[name] = prototype
def create_from_template(self, name: str) -> ReportDocument:
prototype = self._templates.get(name)
if prototype is None:
raise ValueError(f"Unknown template: {name}")
return prototype.clone()
# Usage
if __name__ == "__main__":
# Build expensive prototypes once
financial_template = ReportDocument()
financial_template.title = "Quarterly Financial Report"
financial_template.template_type = "financial"
financial_template.font_family = "Arial"
financial_template.font_size = 11
financial_template.header_text = "CONFIDENTIAL - Financial Report"
financial_template.footer_text = "Generated by Report System v2.0"
financial_template.sections = [
"Executive Summary",
"Revenue Analysis",
"Expense Breakdown",
"Projections",
]
financial_template.metadata = {
"department": "Finance",
"classification": "confidential",
}
tech_template = ReportDocument()
tech_template.title = "Technical Review"
tech_template.template_type = "technical"
tech_template.font_family = "Courier New"
tech_template.font_size = 10
tech_template.header_text = "Engineering - Technical Review"
tech_template.footer_text = "Internal Use Only"
tech_template.sections = [
"Architecture Overview",
"Performance Metrics",
"Risk Assessment",
]
tech_template.metadata = {"department": "Engineering"}
# Register prototypes
registry = DocumentTemplateRegistry()
registry.register("financial", financial_template)
registry.register("technical", tech_template)
# Clone and customize
q1_report = registry.create_from_template("financial")
q1_report.title = "Q1 2025 Financial Report"
print(q1_report)
q2_report = registry.create_from_template("financial")
q2_report.title = "Q2 2025 Financial Report"
print(q2_report)
api_review = registry.create_from_template("technical")
api_review.title = "API Gateway Technical Review"
print(api_review)
# Prove independence — original is unchanged
print(f"Original title: {financial_template.title}")
print(f"Clone title: {q1_report.title}")
Cloneable interface and clone() method are built into Java’s object model, though deep copy must be implemented manually.copy.copy() and copy.deepcopy() provide shallow and deep cloning for any Python object.Instantiate() clones game objects with all their components, used heavily for spawning enemies, projectiles, and particles.