Prototype Pattern — Clone Existing Objects
What You'll Learn
You will learn how the Prototype pattern uses cloning to create new objects without coupling to their concrete classes, and how shallow versus deep copying affects your design. You will also see how a Prototype registry can replace Factory hierarchies.
Why It Matters
Creating objects from scratch can be expensive — think database queries, network calls, or complex initialisation. Prototype lets you clone a pre-configured instance, paying the setup cost once and reusing it many times. It also sidesteps constructor constraints when object configuration is complex. Consider a report template with dozens of configuration options: building each instance from a constructor would require passing all those options every time. With Prototype, you create one fully-configured template and clone it, customising only the fields that differ.
Real-World Use
Game engines clone enemy sprites and weapon objects from a few archetypes rather than constructing each from a Factory — this is why loading a level spawns hundreds of enemies from a handful of Prototype definitions. DodaTech's template engine uses Prototype-based instantiation to stamp out report configurations from a master template, allowing users to define a base report layout once and clone it for different departments with minor tweaks.
The Pattern
A Prototype interface declares a clone method. Concrete prototypes implement cloning to return a copy of themselves. The client clones a Prototype instead of calling a constructor.
import copy
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def clone(self) -> "Shape":
pass
@abstractmethod
def area(self) -> float:
pass
class Rectangle(Shape):
def __init__(self, width: float, height: float, color: str = "red"):
self.width = width
self.height = height
self.color = color
def clone(self) -> "Rectangle":
return copy.deepcopy(self)
def area(self) -> float:
return self.width * self.height
class Circle(Shape):
def __init__(self, radius: float, color: str = "blue"):
self.radius = radius
self.color = color
def clone(self) -> "Circle":
return copy.deepcopy(self)
def area(self) -> float:
return 3.14159 * self.radius ** 2
prototypes = {
"big_rect": Rectangle(100, 50, "green"),
"small_circle": Circle(10, "yellow"),
}
r = prototypes["big_rect"].clone()
r.color = "purple"
c = prototypes["small_circle"].clone()
print(r.area(), r.color)
print(c.area(), c.color)
5000 purple
314.159 yellow
Structure
classDiagram
class Prototype {
<>
+clone(): Prototype
}
class ConcretePrototype1 {
+clone(): Prototype
}
class ConcretePrototype2 {
+clone(): Prototype
}
class Client {
+operation(prototype: Prototype)
}
ConcretePrototype1 ..|> Prototype
ConcretePrototype2 ..|> Prototype
Client --> Prototype : clones
Real-World Usage
- Java
Object.clone()— all Java objects inherit aclone()method for field-by-field copying. - JavaScript
Object.create(proto)— prototypal inheritance is a language-native implementation of this pattern. - Python
copy.copy()andcopy.deepcopy()— the language's standard library implements the Prototype pattern generically. - Godot Engine scenes — scenes are prototypes instantiated throughout a game world.
Related Patterns
- Factory Method is an alternative to Prototype for object creation.
- Abstract Factory can store a registry of prototypes to clone.
- Composite objects often implement cloning to duplicate entire tree structures.
- Memento uses a similar mechanism to capture and restore object state.
Pros and Cons
| Pros | Cons |
|---|---|
| Reduces subclassing for creation | Deep cloning can be complex with circular references |
| Hides concrete product classes | Cloning methods may need special handling for singletons or file handles |
| Performance gain for expensive construction | Not all objects are trivially cloneable |
| Lets you add/remove prototypes at runtime | Shallow copy bugs are subtle and hard to debug |
The code demonstrates deepcopy — essential here because Rectangle and Circle are simple data objects without external resources. The Prototype registry (prototypes dictionary) stores pre-configured instances and clients clone from it rather than calling constructors directly. Notice that modifying the cloned instance's color does not affect the original Prototype.
Practice Questions
- What is the difference between shallow copy and deep copy, and when would each be appropriate?
- Implement a Prototype registry that returns the correct clone based on a string key, registering new prototypes dynamically.
- How would you handle cloning an object that holds a network connection or file handle?
- Compare Prototype with Builder — in what scenarios is each superior?
Challenge
Implement a Prototype registry that supports both cloning and Prototype initialisation callbacks. When a Prototype is cloned, the callback should allow the cloned instance to establish new connections or allocate fresh resources that should not be shared.
Real-World Task
Profile your application with DodaTech's memory profiler to identify objects that are re-created frequently with identical initialisation. Refactor those creation sites to use the Prototype pattern and measure the performance improvement.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro