On this page
Prototype
The Prototype pattern creates new objects by copying an existing instance (prototype) rather than constructing from scratch.
Problem
Object creation is expensive or complex, and you need many similar instances.
Solution
public class Document implements Cloneable {
private String title;
private List<String> pages;
public Document(String title, List<String> pages) {
this.title = title;
this.pages = new ArrayList<>(pages);
}
@Override
public Document clone() {
try {
Document copy = (Document) super.clone();
copy.pages = new ArrayList<>(this.pages); // deep copy mutable fields
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
Document original = new Document("Report", List.of("Page 1", "Page 2"));
Document copy = original.clone();
copy.getPages().add("Page 3"); // does not affect original
Copy Constructor Alternative
Often cleaner than Cloneable:
public class Document {
private final String title;
private final List<String> pages;
public Document(Document other) {
this.title = other.title;
this.pages = new ArrayList<>(other.pages);
}
}
Document copy = new Document(original);
Java Cloneable Issues
The Cloneable interface is widely considered a design flaw:
- Shallow copy by default — mutable fields shared
- No public
clone()method in the interface - Breaks if subclasses forget to override
Prefer copy constructors or factory methods:
public static Document copyOf(Document original) {
return new Document(original.title, new ArrayList<>(original.pages));
}
Java Examples
// Object.clone() — shallow copy
Object copy = original.clone();
// Collections copy
List<String> copy = new ArrayList<>(original);
List<String> copy2 = List.copyOf(original); // immutable copy
// Serialization-based deep copy (legacy approach)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(original);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Document deepCopy = (Document) ois.readObject();
When to Use
- Object creation is costly (database query, complex computation)
- Objects have only a few different configurations
- You need deep copies of complex object graphs
Best Practices
- Prefer copy constructors over
Cloneable - Always deep-copy mutable fields
- Consider immutable objects — no copying needed
- Use serialization libraries (Jackson) for deep cloning complex graphs