The Prototype Design Pattern is a creational design pattern that lets you create new objects by cloning existing ones, instead of instantiating them from scratch.
It’s particularly useful in situations where:
The Prototype Pattern allows you to create new instances by cloning a pre-configured prototype object, ensuring consistency while reducing boilerplate and complexity.
Imagine you have an object in your system, and you want to create an exact copy of it. How would you do it?
Your first instinct might be to:
Simple enough, right?
Well, not quite.
This approach assumes that all fields of the object are publicly accessible. But in a well-designed system, many fields are private and hidden behind encapsulation. That means your cloning logic can’t access them directly.
Unless you break encapsulation (which defeats the purpose of object-oriented design), you can’t reliably copy the object this way.
Even if you could access all the fields, you'd still need to know the concrete class of the object to instantiate a copy.
This tightly couples your cloning logic to the object's class, which introduces problems:
In many cases, your code doesn’t work with concrete classes at all—it works with interfaces.
For example:
Here, you know the object implements a certain interface (Shape
), but you don’t know what class it is, let alone how to create a new instance of it. You’re stuck unless the object knows how to clone itself.
This is where the Prototype Design Pattern comes in.
Instead of having external code copy or recreate the object, the object itself knows how to create its clone. It exposes a clone()
or copy()
method that returns a new instance with the same data.
This:
Let’s walk through a real-world example to see how we can apply the Prototype Pattern to build a more efficient and maintainable object creation workflow.
Let’s say you’re developing a 2D shooting game where enemies appear frequently throughout the gameplay.
You have several enemy types with distinct attributes:
Each enemy type comes with predefined properties such as:
Now, imagine you need to spawn a FlyingEnemy
. You might write code like this:
And you’ll do the same for dozens, maybe hundreds, of similar enemies during the game.
FlyingEnemy
changes, you need to update it in every single place you created one.As your game scales — adding more enemy types, behaviors, or configurations — this naive approach quickly becomes hard to manage and maintain.
You need a clean, centralized, and reusable way to create enemy instances with consistent defaults while allowing minor tweaks.
To avoid repetitive instantiation and duplicated setup logic, we turn to the Prototype Design Pattern.
The Prototype pattern specifies the kinds of objects to create using a prototypical instance and creates new objects by copying (cloning) this prototype.
Instead of configuring every new object line-by-line, we define a pre-configured prototype and simply clone it whenever we need a new instance.
Here’s how it works:
clone()
method, which every cloneable object must implement.FlyingEnemy
, ArmoredEnemy
) implements the Prototype
interface and provides logic to clone itself.new
it directly — it simply asks the prototype object to copy itself.As your system grows with more enemy types or components, you can introduce a Prototype Registry:
"flying"
, "armored"
).Let’s refactor our enemy spawning system in a game using this pattern.
We’ll break the implementation down into 4 clear steps:
EnemyPrototype
)This interface declares a clone()
method, which every cloneable enemy type must implement.
Enemy
)This is the actual class that we want to clone. It implements the EnemyPrototype
interface and defines the cloning behavior using a copy constructor, which is a clear and reliable way to clone objects in Java.
String
). But if Enemy
had a field like a List
, both the original and cloned enemies would share the same list object, which can cause subtle bugs.Java’s built-in Object.clone()
is often avoided due to its limitations and shallow behavior. Manual cloning using copy constructors or builders is more flexible and safer.
EnemyRegistry
)A Prototype Registry (or Manager) stores pre-configured prototype instances. This keeps your code organized, especially when you have many types of enemies.
Now your game logic can fetch enemies by type without worrying about how they’re constructed.
Here’s how everything comes together in the main game loop or enemy spawner logic: