low-level-design4 min read

Prototype Pattern Tutorial from Scratch (2026)

Prototype Pattern Tutorial from Scratch (2026)

Published:  |  Category: Low Level Design  |  Reading time: ~15 min
Prototype Pattern Tutorial from Scratch (2026)

The Prototype pattern creates new objects by copying an existing object, known as the prototype, rather than instantiating a class directly. This approach is particularly useful when object creation is expensive or when the system should be independent of how its objects are created and composed.

In this tutorial, you will explore cloning mechanisms in Java and C++, understand the critical difference between shallow and deep copy, implement a prototype registry for managing reusable prototypes, and see how JavaScript achieves prototypal inheritance through Object.create().

Cloneable Interface and Shallow Copy in Java

Java supports the Prototype pattern via the Cloneable marker interface and the protected clone() method from Object. A class must implement Cloneable and override clone() to make it public. Shallow copy duplicates the object's fields but shares references to mutable child objects, which can cause unintended side effects.

class Shape implements Cloneable {
    private String id;
    private String type;
    private List points;

    public Shape(String id, String type, List points) {
        this.id = id;
        this.type = type;
        this.points = points;
    }

    @Override
    public Shape clone() {
        try {
            // Shallow copy - points list is shared!
            return (Shape) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

    // For deep copy
    public Shape deepClone() {
        List clonedPoints = points.stream()
            .map(p -> new Point(p.x, p.y))
            .collect(Collectors.toList());
        return new Shape(this.id, this.type, clonedPoints);
    }
}

// Usage
Shape original = new Shape("1", "circle", List.of(new Point(0, 0)));
Shape cloned = original.clone();
System.out.println(cloned != original);        // true
System.out.println(cloned.getClass() == original.getClass()); // true

Deep Copy vs Shallow Copy

Deep copy creates a completely independent copy of the object graph, duplicating all referenced objects recursively. Shallow copy is faster but can lead to bugs when mutable child objects are modified through one reference and unexpectedly affect the other. The choice depends on whether the object graph should be shared or isolated.

class DeepCopyExample {
    private int[] data;
    private Map configMap;

    public DeepCopyExample deepCopy() {
        DeepCopyExample copy = new DeepCopyExample();
        copy.data = this.data.clone();  // primitive array
        copy.configMap = new HashMap<>();
        for (Map.Entry entry : this.configMap.entrySet()) {
            copy.configMap.put(entry.getKey(), entry.getValue().clone());
        }
        return copy;
    }
}

// C++ copy constructor for deep copy
class Document {
    char* buffer;
    size_t size;
public:
    Document(const Document& other)
        : size(other.size)
        , buffer(new char[other.size])
    {
        std::copy(other.buffer, other.buffer + size, buffer);
    }

    Document& operator=(const Document& other) {
        if (this != &other) {
            delete[] buffer;
            size = other.size;
            buffer = new char[size];
            std::copy(other.buffer, other.buffer + size, buffer);
        }
        return *this;
    }

    ~Document() { delete[] buffer; }
};

Prototype Registry

A prototype registry stores a collection of pre-configured prototype objects that can be cloned on demand. This eliminates subclass proliferation for every configuration variant and makes it easy to add or remove prototype variants at runtime. The registry is typically implemented as a hash map keyed by string identifiers.

class PrototypeRegistry {
    private Map prototypes = new HashMap<>();

    public void registerPrototype(String key, Shape prototype) {
        prototypes.put(key, prototype);
    }

    public Shape createClone(String key) {
        Shape prototype = prototypes.get(key);
        if (prototype == null) {
            throw new IllegalArgumentException("Unknown prototype: " + key);
        }
        return prototype.clone();
    }
}

// Initialization
PrototypeRegistry registry = new PrototypeRegistry();
registry.registerPrototype("circle", new CircleShape(10.0, "red"));
registry.registerPrototype("rectangle", new RectangleShape(5.0, 3.0, "blue"));

// Usage
Shape circle1 = registry.createClone("circle");
Shape circle2 = registry.createClone("circle");
Shape rect = registry.createClone("rectangle");

Frequently Asked Questions

When is Prototype pattern preferable to Factory Method?

Prototype is preferable when object creation is expensive (e.g., database queries, complex calculations), when the classes to instantiate are specified at runtime (e.g., loaded from configuration), or when you want to avoid building a parallel class hierarchy of factories for every product variant.

How do I implement clone in Java correctly?

Implement Cloneable, override clone() making it public, and call super.clone(). For deep copy, manually copy mutable fields after the super.clone() call. Consider using copy constructors or serialization-based cloning for complex object graphs instead of Cloneable.

What is the difference between shallow and deep copy?

Shallow copy copies the object's field values directly, so reference fields point to the same objects as the original. Deep copy recursively duplicates all referenced objects, creating a fully independent copy. Shallow copy is faster but shares mutable state.

Does JavaScript use the Prototype pattern?

Yes, JavaScript uses prototypal inheritance natively. Object.create(proto) creates a new object with the specified prototype, making it a built-in implementation of the Prototype pattern. This is fundamentally different from classical inheritance and is a core part of JavaScript's object model.

Originally published on Ayodhyyya. Last updated June 1, 2026.