Definition
The Prototype design pattern is a creational pattern that allows for the creation of new objects by copying existing objects, which serve as prototypes.
This pattern is particularly useful when the cost of creating a new object is prohibitive or when a system wants to avoid subclasses proliferation.
Common Use Cases
You’d use the pattern when:
- you have resource-intensive object creation. When the cost of creating a new object is high in terms of time or resources, cloning an existing object can be much more efficient. For example, in graphic applications where creating a new graphic object (like a complex shape) is resource-intensive, cloning an existing one is preferred.
- you want to avoid subclass proliferation. If a system has a complex hierarchy of classes and creating new combinations of state requires creating new subclasses, the Prototype pattern can be used to simplify this by cloning existing objects and modifying their state.
- you need dynamic object creation. When the type of objects to be created is decided at runtime, the Prototype pattern allows for creating objects without knowing their exact types at compile time.
- you need state preservation. In scenarios where an object needs to be saved and restored, such as in undo operations in text editors or other applications, cloning can help in preserving the state of the object.
Example of Resource-Intensive Object Creation
Let’s consider a scenario in a graphic design application where creating a complex graphic object, such as a fractal, is resource-intensive. Instead of creating new fractals from scratch each time, we can create a prototype of a fractal and clone it whenever needed.
Suppose we have a Fractal
class that is computationally expensive to create. We will use the Prototype pattern to clone existing fractals instead of creating new ones.
Fractal Class
|
|
Prototype Manager Class
|
|
Client Code
|
|
Explanation
-
Fractal
is an abstract class that defines theClone
andDraw
methods.MandelbrotFractal
is a concrete implementation ofFractal
that simulates a resource-intensive creation process through a simple timeout. -
FractalManager
is a class that manages the prototypes of fractals. It allows registering a fractal prototype with a specific key and retrieving a clone of the fractal using that key. -
In the
Main
method of the client code, aFractalManager
instance is created, and aMandelbrotFractal
prototype is registered with it. The fractal is then cloned multiple times, and each clone is drawn. The resource-intensive creation process (simulated by a sleep) only happens once when the prototype is created. Subsequent clones are created quickly by copying the prototype.
Example of Subclass Proliferation
Let’s dive a game development context where we have different types of game characters. Each character can have various attributes such as health, attack power, and defense, and different combinations of these attributes might require creating many subclasses if we don’t use the Prototype pattern.
By using the Prototype pattern, we can avoid subclass proliferation by cloning existing character prototypes and modifying their attributes as needed.
Suppose we have a base GameCharacter
class and several types of characters (e.g., Warrior, Mage) that share common attributes but may need customization.
Imagine we have 5 base character types (Warrior, Mage, Archer, Rogue, Cleric). Each needs 3 variants (Basic, Elite, Legendary). Without Prototype, you’d need 15 subclasses.
|
|
We face the following Problems:
- ❌ Exploding number of subclasses
- ❌ Hard to maintain
- ❌ No runtime flexibility
Let’s apply the Prototype Pattern to simplify the classes.
GameCharacter Class
First, let’s abstract the GameCharacter
:
|
|
And define the necessary subclasses:
|
|
Client Code of the Game
Let’s put this to the test.
|
|
Explanation of the Game
- Like in the first example, GameCharacter Class represents an abstraction and defines the
Clone
andDisplay
methods.Warrior
andMage
are concrete implementations ofGameCharacter
. Each subclass implements theClone
method usingMemberwiseClone()
to create a shallow copy of the object. - In the
Main
method of the client code, prototypes ofWarrior
andMage
are created. The enhanced characters are then cloned from the basic character, and their attributes are customized as needed. TheDisplay
method outputs the clones’s value and it shows the original prototype isn’t affected.
The key benefits are as follows:
- Eliminated 12 subclasses (from 15 to 3 classes)
- Runtime customization without recompiling
- Centralized configuration through prototypes
- Easier maintenance - changes propagate to all clones
This shows how Prototype helps avoid combinatorial explosion of subclasses when dealing with multiple variation axes (character type + variant tier in this case).
Resources to Read
You need more details on this design pattern?
You can read:
- Gamma, Erich, et al. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994. This is the seminal book that introduced the Prototype pattern among other design patterns.
- Freeman, Eric, and Elisabeth Freeman. Head First Design Patterns. O’Reilly Media, 2004. This book provides an accessible and engaging introduction to design patterns, including the Prototype pattern.
- Microsoft Docs: The official Microsoft documentation on design patterns includes explanations and examples of the Prototype pattern.
- Prototype Pattern Explained: When Copying is Smarter Than Creating de Maxim Gorin : the article explains the topic very well, in my opinion.
These references can provide further reading and context on the Prototype pattern and its use cases. My article is my take on it and my notes for future reference.
Follow me
Thanks for reading this article. Make sure to follow me on X, subscribe to my Substack publication and bookmark my blog to read more in the future.
Photo by Senne.