Connect with me
Creational Design Pattern: Prototype
The Prototype Design Pattern is a creational pattern that lets us create new objects by cloning existing ones instead of instantiating them from scratch.

This article is part of a series exploring design patterns using the Java programming language. The goal of this series is to help readers develop a solid understanding of design patterns while also sharing real-world examples from actual codebases that make use of these patterns.
In this article, we’ll be discussing the Prototype pattern.
Symbols for better navigation:
🤔 Hypothetical Scenario/Imagination
⚠️ Warning
👉 Point to note
📝 Common Understanding
Prototype Pattern
The Prototype Design Pattern allows the creation of new objects by cloning an existing prototype.
A prototype acts like a mold or template that can be reused to generate multiple objects.
Consider a scenario where we need to create several objects of the same type, but each with a different state. A common example of this is UI elements.
🤔 For instance, suppose we want to create labels in a form UI with predefined properties such as span, font size, and style. It would be inefficient for a developer to reinitialize such elements from scratch every time. Instead, they could simply use a prototype of the label element and create a new Label instance whenever needed.
Take a look at this example.
public class TestPrototype {
public static void main(String[] args) {
Label l = new Label("My Label", 3, true);
Label l2 = l.clone(); // prototyping
l2.setText("My Label 2");
}
}
In this example, we are performing a shallow clone of the Label
object to create a new label with the same properties/state. This demonstrates the basic working of the Prototype Pattern, which is creating new objects by copying existing ones instead of constructing them from scratch.
👉 However, the Prototype Pattern goes beyond simple cloning. A common enhancement is to maintain a registry of prototype objects that can be reused to create new instances.
For example, take a look at this code.
public class TestPrototype {
public static void main(String[] args) {
Registry reg = Registry.getRegistry();
Label myNewLabel = reg.createItem("label"); // getting prototypes from registry
}
}
Here, instead of manually cloning objects, we retrieve prototypes from a centralized registry and use them to create new objects.
📈 Creation of similar types of objects via prototype design patterns then has multiple advantages:
- Avoids costly instantiation: Objects can be created more efficiently by cloning rather than repeatedly calling constructors, which saves developer effort.
- Reduces subclassing: New types of objects can be stored in the registry as prototypes and reused without the need to create separate subclasses.
- Centralized prototype registry: All prototypes are maintained in one place, making object creation more organized and easier to manage.
- Pre-established contract defaults: This means the developer doesn’t have to fill default property values on object creation.
Recipe to cook Prototype Pattern for objects
Utilizing the Prototype Pattern for object creation is simple. The idea is to make our objects cloneable and keep a registry of prototype instances that can be reused across the system.
🤔 For example, let’s say I have a Label object as follows.
public class Label {
private String text;
private int span;
private boolean visible;
private Props props;
public Label(String text, int span, boolean visible, Props props) {
this.text = text;
this.span = span;
this.visible = visible;
this.props = props;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getSpan() {
return span;
}
public void setSpan(int span) {
this.span = span;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public Props getProps() {
return props;
}
public void setProps(Props props) {
this.props = props;
}
}
To convert this into a prototype, I’ll first make it cloneable as follows.
public class Label implements Cloneable {
private String text;
private int span;
private boolean visible;
private Props props;
public Label(String text, int span, boolean visible, Props props) {
this.text = text;
this.span = span;
this.visible = visible;
this.props = props;
}
@Override
protected Label clone() {
try {
Label cloned = (Label) super.clone(); // shallow clone
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Cloning is not supported", e);
}
}
// Getters and setters...
}
⚠️ But there’s one issue with this code, if you observe, the props
property of the Label
class is also an object. And when we try to override the clone method, it only creates a shallow copy of the Label
object.
Shallow copy means that only the immediate property values, viz., text, span and visible, are copied. However, when it comes to props, a new object of type Prop
will be initialized with null
values.
A more elaborate explanation of this means that, suppose the Prop
class had one property named name
, then instead of copying the actual value in the cloned object of the Label
, it will create a new prop
property with an initial name
value.
👉 To prevent this, we have to perform a deep cloning of the Label object by overriding the Label
class clone
method as follows.
protected Object clone() throws CloneNotSupportedException {
try {
Label clonedLabel = (Label) super.clone(); // shallow cloning
clonedLabel.setProps(this.props.clone()); // props should be cloneable!
return clonedLabel();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
This method will now create a deep copy of the Label
object. ⚠️ However, we should note that the Props
class too should be a cloneable and must have overridden the clone method in its own class.
Now, the last step in the prototype is to create a registry of the prototypes so that they can be reused globally anywhere in our code.
public class Registry {
private Map<String, Label> items = new HashMap<>();
private Registry() {
loadItems();
}
private static class RegistryHolder {
private static final Registry INSTANCE = new Registry();
}
public static Registry getRegistry() {
return RegistryHolder.INSTANCE;
}
private void loadItems() {
items.put("label", new Label("Default Label", 3, true, new Props("default-prop")));
}
public Label createItem(String itemName) {
Label prototype = items.get(itemName);
return prototype != null ? prototype.clone() : null;
}
}
Finally, let’s bring all of this together in our code.
public class TestPrototype {
public static void main(String[] args) {
Registry registry = Registry.getRegistry();
Label l1 = registry.createItem("label"); // registry access
l1.setText("First Label");
Label l2 = registry.createItem("label");
l2.setText("Second Label");
l2.getProps().setName("custom-prop"); // set values
}
Disadvantages of Using Prototypes
- Collections of Prototypes in a registry resemble that of a framework rather than a pattern.
- Shallow and Deep Cloning both require manual implementation.
Up Next in the Series
Factory Design Pattern
Subscribe to my newsletter today!