skip to content

questions

6

What problem does the Prototype creational design pattern solve, and how does it produce new objects?

level: juniorimportance: must knowfreq 55%

answer

  1. Copy a configured exemplar, not a constructor call
  2. Expensive or fiddly instantiation
  3. clone() behind an abstract type
  4. Registry of exemplars = variants as data
  5. Real difficulty is shallow vs deep copy

basics

~20 s

Prototype creates a new object by copying an existing, already-configured object instead of building one from scratch. You ask the existing instance to clone itself. It helps when construction is slow or the setup is long and fiddly.

solid answer

~50 s

Prototype is a creational pattern whose intent is: create new objects by copying a prototypical instance rather than invoking a constructor and re-running the whole configuration. The prototype exposes a single operation — conventionally `clone()` or `copy()` — that returns a new object of the same concrete type with equivalent state. Callers hold the prototype through an abstract type, so they can duplicate an object without knowing its concrete class or its construction recipe. It pays off when instantiation is expensive (parsed configuration, precomputed tables, data loaded over the network) or configuration-heavy (dozens of setters/options that would otherwise be duplicated at every call site), and when the set of variants is decided at runtime — you register configured exemplars instead of writing a subclass or factory branch per variant. The hard part is not the pattern shape but copy semantics: deciding, field by field, what gets duplicated and what gets shared.

code

pseudocode · 14 lines
pseudocode
interface Shape { Shape clone(); void draw(); }

class Circle implements Shape {
  Point center; int radius; Style style;
  Shape clone() {
    // decide per field: duplicate or share
    return new Circle(center.copy(), radius, style); // style is immutable -> shared
  }
}

// client knows only the abstract type
Shape tool = palette.get("circle");   // a configured prototype
Shape placed = tool.clone();          // new object, no constructor knowledge
placed.moveTo(cursor);

go deeper

for a junior

State the intent — new objects by copying an existing configured one via clone() — and one motivating case such as expensive setup.

for a middle

Add the three roles plus the registry, contrast with Factory Method and Builder, and raise shallow vs deep copy as the real design decision.

for a senior

Discuss copy semantics field by field, aliasing bugs, cycles and shared references, non-copyable state (IDs, connections, listeners), and cost of deep copy versus rebuilding.

for a principal

Frame it as a decision about ownership and mutability: prefer immutability and sharing where possible; treat copy semantics as part of the type's contract, tested and documented, rather than an incidental method.

### The words first - **Creational pattern**: a reusable design solution concerned with *how objects get made*, so that the code needing an object is decoupled from the details of making it. Prototype, Factory Method, Abstract Factory, Builder and Singleton are the classic five. - **Instance**: one concrete object in memory, with its own field values. - **Prototype (here)**: an already-existing, already-configured instance that is kept around specifically so that other objects can be produced from it by copying. - **Clone / copy**: produce a new object whose state is equivalent to an existing one. ### The intent > *Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.* Normal object creation is **construction**: call a constructor, then run whatever setup the object needs. Prototype replaces that with **duplication**: take an object that is already in the desired state and ask it for a copy. ### Shape of the pattern Three roles: 1. **Prototype** — an abstract type (interface/abstract class) declaring a copy operation, e.g. `Shape { Shape clone() }`. 2. **ConcretePrototype** — each real class implements the copy operation, returning a new object of its own type. 3. **Client** — holds a `Shape` reference and calls `clone()`. It never names `Circle`, `Polygon`, `BezierPath`, and never knows how any of them are built. Optionally there is a fourth role, the **prototype registry** (a.k.a. prototype manager): a map from key → configured prototype, so `registry.get("warning-dialog").clone()` yields a ready-made object. ### Why you would reach for it - **Expensive instantiation.** The object's real cost is not allocating memory but the work behind it: reading a file, parsing a grammar, compiling a regex, warming a lookup table, doing a database round-trip. If that work produces a value that can be copied cheaply, do it once into a prototype and clone thereafter. - **Configuration-heavy setup.** An object needing 15 options set in a precise order is error-prone to build repeatedly. Build one exemplar, validate it, then clone-and-tweak: `var d = defaultDialog.clone(); d.title = "Delete?";`. - **Runtime-decided variants.** Instead of a `switch` over types (which must be edited for every new variant) or one factory subclass per product, you *register instances*. Adding a new variant becomes adding data — a new configured prototype — not new code. Graphical editors do exactly this: a palette of tools where each tool is a prototype shape; dropping one onto the canvas clones it. - **Preserving state you cannot reconstruct.** Sometimes the only way to get an object into a given state is to have gone through the interactions that got it there. Copying preserves it; constructing cannot. - **Undo/snapshot-style features** often lean on the same copy machinery (though the *pattern* for that is Memento). ### Why it is riskier than it looks The pattern's whole substance collapses into one question: **what does "a copy" mean for this object?** - A **shallow copy** duplicates the object's own fields; fields that are references still point at the *same* nested objects, now shared between original and copy. Mutating a shared nested object is visible through both — action at a distance, a classic aliasing bug. - A **deep copy** recursively duplicates the reachable object graph, so the copy is independent. It costs more time and memory, and it must cope with shared references and cycles, and with parts that *must not* be duplicated (identities, open connections, locks, listeners). So Prototype is trivial to draw and non-trivial to get right; the difficulty lives in the copy, not in the pattern diagram. ### Relation to neighbouring patterns - **Factory Method / Abstract Factory** create by *calling code* keyed on a type; Prototype creates by *copying data*. Factories tend to need a class per product; Prototype needs an instance per variant. - **Builder** assembles a complex object step by step; Prototype skips assembly by reusing a finished one. They combine well: build once, clone many. - **Memento** captures state for later restoration rather than for producing sibling objects. - **Flyweight** deliberately *shares* instead of copying — the opposite trade-off, valid when the state is immutable. ### When *not* to use it If objects are immutable, copying is pointless — share the instance instead. If construction is cheap and clear, a constructor or factory is easier to read and to test. If the object owns external resources (sockets, file handles, threads), "copy" may have no coherent meaning and the pattern will invite bugs.

  • How is Prototype different from a factory that returns preconfigured objects?
    A factory builds by executing construction code chosen by type key, so a new variant usually means new code (a branch, a subclass). Prototype builds by duplicating a stored instance, so a new variant is a new piece of data — register another configured exemplar. Prototype also preserves state that construction could not reproduce.
  • If a class is immutable, is Prototype still useful?
    Rarely for copying — immutable objects can be shared safely, so cloning only wastes memory. Prototype still has value as a way to keep a catalogue of ready-made exemplars, but the copy operation itself can legitimately return `this`.

A print shop keeps a signed master copy of a poster. Producing another poster means running the master through the copier, not re-drawing the artwork. The master is the prototype; the copier is clone(). The catch: if the master has a real ribbon glued to it, the copy only gets a picture of the ribbon — that gap is the shallow-versus-deep-copy problem.

saying these in an interview costs you the question

  • "Prototype is just another name for a factory" — factories execute construction code, Prototype duplicates an existing instance.
  • Assuming `clone()` is automatically a deep copy.
  • Using Prototype for immutable objects, where sharing is strictly better.
  • Cloning objects that own external resources (sockets, handles, threads) as if the resource could be duplicated.
  • Thinking the pattern is complete once a `clone()` method exists, without deciding per-field copy semantics.

context

open as a page

When implementing a copy operation for the Prototype pattern, what is the difference between a shallow copy and a deep copy, and what bug does choosing wrongly cause?

level: middleimportance: must knowfreq 70%

basics

~20 s

A shallow copy duplicates the object's own fields, so reference fields still point at the same nested objects — original and copy share them. A deep copy also duplicates those nested objects. Choosing shallow wrongly means editing the copy silently changes the original.

open as a page

What is a prototype registry, and when would you prefer registering configured prototypes over adding another factory or subclass?

level: middleimportance: should knowfreq 40%

basics

~20 s

A prototype registry is a lookup table from a key to a ready-made, configured object. Clients ask for a key and clone what comes back. You prefer it when new variants differ only in configuration, so adding one means adding data, not code.

open as a page

How do you implement a correct deep copy of an object graph that contains cycles and objects referenced from more than one place?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Carry a map from each already-copied original object to its copy. Before copying anything, look it up: if it is in the map, reuse that copy instead of recursing. This stops infinite loops on cycles and keeps shared objects shared in the copy.

open as a page

When cloning an object with the Prototype pattern, which parts of its state should NOT be copied verbatim, and what should happen to them instead?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Anything that identifies the object or ties it to the outside world: database IDs, creation timestamps, version counters, open connections and file handles, locks, caches and registered listeners. These should be reset, regenerated, or re-established rather than duplicated.

open as a page

Serializing an object and immediately deserializing it is a popular way to get a deep copy. What are the trade-offs of that technique, and what would you prefer at scale?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Serialize-then-deserialize gives a deep copy in one line and handles nested structures generically. But it is slow, copies everything including things you should not copy, silently drops fields the format cannot represent, and can lose shared references or fail on cycles.

open as a page