Facebook Pixel

Prototype

The Prototype pattern creates new objects by cloning an existing instance rather than constructing one from scratch. When constructing an object is expensive — because it requires a database lookup, network call, or lengthy computation — and you need many similar instances, cloning a pre-built template is faster than repeating that work for each new object.

The pattern also solves a coupling problem. If a caller knows only that it holds a reference to some interface, it cannot call new ConcreteTypeItDoesntKnowAbout(...) to copy it. But if the interface exposes a clone() method, the caller can duplicate the object without knowing its runtime type.


Each concrete class implements clone() by copying itself. The caller holds a Prototype reference and calls clone() without knowing whether it is duplicating a DocumentTemplate or a ReportTemplate.

Shallow copy vs deep copy

The central design decision in any clone() implementation is how to treat nested mutable objects. A shallow copy copies the object's own fields by value but shares references to any nested objects. A deep copy recursively copies every nested object as well.

The distinction matters when the cloned object is then modified. With a shallow clone, mutating a nested list or map in one copy changes the same underlying structure in the original — the two copies are not truly independent. With a deep clone, each copy owns its own data.

Consider a DocumentTemplate that holds a list of section objects and a style dictionary. If two editors each clone the template and then modify their own copy, a shallow clone causes their changes to interfere with each other. A deep clone prevents this.

The trade-off is performance. A deep copy of a document with many nested objects is more expensive than a shallow copy. When the nested data is read-only or immutable, a shallow copy is safe and faster. When callers may mutate the nested objects, a deep copy is required.

Bad → Good

Without the Prototype pattern, a caller that wants a modified copy of a pre-configured object must either reconstruct it from scratch (repeating the setup) or reach into its internals to extract values and re-pass them to a constructor.

1# Bad: reconstructing from scratch couples the caller to all constructor
2# parameters and repeats any expensive setup.
3class DocumentTemplate:
4    def __init__(self, title: str) -> None:
5        self.title = title
6        self.sections: list[str] = []
7        self.styles: dict[str, str] = {}
8        self._load_styles_from_db()   # expensive — hits the database
9
10    def _load_styles_from_db(self) -> None:
11        # Simulate a slow lookup
12        self.styles = {"font": "Arial", "size": "12pt", "color": "#333"}
13
14# Every copy forces a database hit, and the caller must know all parameters.
15quarterly_report = DocumentTemplate("Q1 Report")
16quarterly_report.sections = ["Executive Summary", "Financials"]
17
18# To make a similar Q2 report, we repeat the whole construction:
19q2_report = DocumentTemplate("Q2 Report")   # another DB hit
20q2_report.sections = ["Executive Summary", "Financials"]  # manually copied

With Prototype, the expensive setup happens once. Callers clone the cached template and adjust only what differs. The deep copy in Python uses copy.deepcopy, which recursively copies every nested object so that modifications to one clone do not affect the original or other clones.

Invest in Yourself
Your new job is waiting. 83% of people that complete the program get a job offer. Unlock unlimited access to all content and features.
Go Pro