Skip to content
FollowtheDamnCode

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

Clients clone samples from a registry

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.

Shallow copies share nested lists; deep copies don't
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: False

Run 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

  1. Add a clone() method to the prototype interface.
  2. Implement it per class, deciding for each field: share it (immutable or intentionally shared) or copy it (mutable, owned).
  3. Watch out for objects that shouldn't be duplicated — open files, database connections, unique IDs — and reset them in the clone.
  4. 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

ProsCons
Avoids repeating expensive setupDeep vs shallow copy bugs are subtle
Clients don't need concrete classesCloning objects with resources or cycles is tricky
Runtime-configured templates become typesEach 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.