Prototype
Create new objects by copying a configured sample, without knowing (or re-running) how it was built.
Big idea
Prototype creates objects by cloning an existing, fully configured instance instead of constructing from scratch. The client calls clone() and gets an independent copy — without knowing the concrete class, and without repeating expensive setup. The crucial detail is deep versus shallow copy.
The problem it solves
A survey tool has a "customer satisfaction" template: twelve questions, each with options, validation rules, and translations loaded from files. Every new survey starts from it. Rebuilding it with constructors repeats a lot of slow, fiddly setup — and the code doing it must know every question class. Copying field by field from outside fails too: private fields aren't reachable, and the copier now depends on every class it copies.
Think of it like
A locksmith cutting a key. They don't need the lock's blueprints or the factory's machine settings — they clamp your existing key in and copy it. The new key is independent: lose one, the other still works.
Structure
In code
Python's copy module does the heavy lifting: copy.copy is shallow (the new object shares nested objects), copy.deepcopy copies the whole graph.
import copy
class Survey:
def __init__(self, title, questions):
self.title = title
self.questions = questions # a nested, mutable list
def clone(self):
return copy.deepcopy(self) # an independent copy of the whole graph
template = Survey("Satisfaction", [["How was delivery?", ["good", "bad"]]])
shallow = copy.copy(template)
shallow.title = "Shallow copy"
shallow.questions[0][1].append("meh") # oops: mutates the template's list too
print(template.title, template.questions[0][1])
deep = template.clone()
deep.title = "Deep copy"
deep.questions[0][1].append("excellent") # only the clone changes
print(template.title, template.questions[0][1])
print(deep.title, deep.questions[0][1])
class TemplateRegistry:
def __init__(self):
self._samples = {}
def add(self, name, proto):
self._samples[name] = proto
def create(self, name):
return self._samples[name].clone() # callers never name the class
registry = TemplateRegistry()
registry.add("nps", Survey("NPS", [["Recommend us 0-10?", list(range(11))]]))
a, b = registry.create("nps"), registry.create("nps")
a.title = "NPS - March"
print(a.title, "|", b.title, "| same object:", a is b)output
Satisfaction ['good', 'bad', 'meh']
Satisfaction ['good', 'bad', 'meh']
Deep copy ['good', 'bad', 'meh', 'excellent']
NPS - March | NPS | same object: FalseRun and edit it in the app.
The shallow copy looked like a separate survey, but it shared the options list with the template — every survey created afterwards inherited "meh". That's the bug Prototype implementations must avoid.
Watch it
How to implement it
- Add a
clone()method to the prototype interface. - Implement it per class, deciding for each field: share it (immutable or intentionally shared) or copy it (mutable, owned).
- Watch out for objects that shouldn't be duplicated — open files, database connections, unique IDs — and reset them in the clone.
- Optionally keep a registry of named, preconfigured prototypes.
After clone = copy.copy(original), you append to clone.items, a list. What happens to original.items?
When to use it — and when not to
Use it when creating an object is expensive and you need many similar ones, when objects are configured at runtime (a user designs a template and wants copies), or when you want new objects without coupling to their concrete classes.
Skip it when construction is cheap and simple, and be careful with object graphs containing cycles or external resources — deep copies can be surprising.
Pros and cons
| Pros | Cons |
|---|---|
| Avoids repeating expensive setup | Deep vs shallow copy bugs are subtle |
| Clients don't need concrete classes | Cloning objects with resources or cycles is tricky |
| Runtime-configured templates become types | Each class must implement clone correctly |
How it relates
- An alternative to Factory Method: instead of a creator subclass per product, keep a sample per product.
- Composite and Decorator structures often benefit from cloning whole subtrees.
- Memento also copies state, but to restore it later rather than to create new objects.
A prototype object holds an open network connection. What should clone() do with it?
Key terms
- Prototype — A configured object used as a template for creating new objects by copying.
- Shallow copy — A new outer object that still shares the original's nested objects.
- Deep copy — A copy of an object and, recursively, everything it owns.
- Prototype registry — A lookup of named prototypes that callers clone from.