Browse Java Design Patterns & Enterprise Application Architecture

Implementing Prototype in Java

Implement Prototype in Java with explicit copy semantics first, then use Cloneable only when an API or legacy model truly requires it.

Prototype: A pattern where a preconfigured object produces new instances by copying its current state instead of rebuilding from scratch.

In Java, Prototype is less about the clone() method than older tutorials suggest. The real design problem is how to create a new object from an existing one without accidentally sharing mutable state or hiding important construction rules.

Start With Explicit Copying

The cleanest modern Java implementation is often a copy constructor or named copy factory:

 1public final class ReportTemplate {
 2    private final String title;
 3    private final List<String> sections;
 4    private final Map<String, String> defaults;
 5
 6    public ReportTemplate(String title,
 7                          List<String> sections,
 8                          Map<String, String> defaults) {
 9        this.title = title;
10        this.sections = List.copyOf(sections);
11        this.defaults = Map.copyOf(defaults);
12    }
13
14    public ReportTemplate(ReportTemplate source) {
15        this(source.title, source.sections, source.defaults);
16    }
17
18    public ReportTemplate copyWithTitle(String newTitle) {
19        return new ReportTemplate(newTitle, sections, defaults);
20    }
21}

This is still Prototype. The prototype is the existing ReportTemplate. What matters is that the copy rule is explicit and safe.

Why clone() Is Not The Default Recommendation

Java supports Cloneable, but it comes with awkward semantics:

  • Cloneable is a marker interface with no explicit copy contract
  • Object.clone() is shallow unless you do more work
  • checked exception handling adds noise
  • subclassing can make copy rules harder to reason about

That does not make clone() unusable. It means the design should justify it. In most application code, explicit copy logic is clearer than inheriting clone() conventions.

Choose The Copy Boundary Deliberately

The important decision is what the copy owns.

If the object only contains immutable values, copying can be cheap and straightforward. If it contains collections, caches, file handles, sockets, locks, or references to shared services, then “copying the object” may be the wrong operation entirely.

Ask:

  • which fields should be duplicated
  • which fields can be safely shared
  • which fields should be recomputed instead of copied
  • whether the copy should preserve identity-like fields such as IDs or timestamps

Shallow And Deep Copy Are Design Choices

A shallow copy duplicates the top-level object while keeping references to nested objects. A deep copy duplicates the nested graph as well. Neither is automatically correct.

Shallow copy is reasonable when nested state is immutable or intentionally shared. Deep copy is necessary when the new object must evolve independently.

 1public final class OrderDraft {
 2    private final Customer customer;
 3    private final List<LineItem> items;
 4
 5    public OrderDraft(OrderDraft source) {
 6        this.customer = source.customer; // shared immutable reference
 7        this.items = source.items.stream()
 8            .map(LineItem::copy)
 9            .toList();
10    }
11}

The copy policy is visible here. That is the goal.

Common Implementation Shapes

ApproachGood fitMain caveat
Copy constructorMost application-domain typesCan get verbose for large object graphs
Static copy factory such as from(existing)Named or role-specific copiesStill needs explicit field policy
clone() / CloneableLegacy APIs, frameworks, or established inheritance treesEasy to hide shallow-copy bugs
Builder seeded from an existing objectMany optional changes during copyMore moving parts than a direct copy

For a deeper comparison, see Copy Constructors and Cloning Alternatives.

When Prototype Helps

Prototype is useful when:

  • initialization is expensive or repetitive
  • a configured template should produce many similar instances
  • callers need a safe starting point they can customize
  • rebuilding an object graph from raw parameters would be noisy or error-prone

Good examples include document templates, preconfigured request objects, workflow drafts, test fixtures, and game or UI templates.

When It Is A Bad Trade

Prototype is a weak choice when:

  • the object manages live resources such as connections or threads
  • copy semantics are too ambiguous to explain simply
  • the copied state includes mutable collaborators that should not be duplicated
  • construction rules are better expressed by a builder or factory

If readers cannot quickly answer what is copied, shared, and reset, the pattern is probably the wrong abstraction.

Where To Go Deeper

This page keeps the implementation shape self-contained, then pushes detail outward:

Design Review Questions

When reviewing a Prototype implementation in Java, ask:

  • Is the copy policy explicit enough to reason about?
  • Which nested objects are shared and why?
  • Would a copy constructor or static factory be clearer than clone()?
  • Are identity, timestamps, and mutable collections handled correctly?

Prototype is helpful when the copy boundary is part of the design. It is dangerous when copying is treated as a shortcut around thinking about state ownership.

Loading quiz…
Revised on Thursday, April 23, 2026