LLD Dojo

Prototype

Occasional. Turns up in specific problems. Worth recognising and being able to sketch, not worth drilling.

Start with the problem

corpus/parking-lot's Vehicle is a record of two fields, a registration and a type.

public record Vehicle(String registration, VehicleType type) {}

Suppose the lot runs a corporate fleet program. Every fleet car shares one type, CAR, and gets a registration in a fixed series, FLEET-001, FLEET-002, and so on. Checking one in is one line: new Vehicle("FLEET-" + next, VehicleType.CAR). With two fields, there is nothing to copy from anywhere. Writing the values out by hand each time is fine.

Watch where it goes

Vehicle grows a third field, a loyalty tier, and later a fourth, an EV flag. Now every place that builds "a car like the last fleet car, but with the next registration" has to remember every field, in order, every time. Forgetting one is silent. The new vehicle gets a default tier nobody meant, and nothing fails, because the constructor took whatever it was given.

The move, GoF's version

The classic fix is to give the type a clone() method, so a variation is "copy the template, then change one field" instead of "recite every field again."

public final class MutableVehicle implements Cloneable {
    private String registration;
    private String tier;

    @Override
    public MutableVehicle clone() throws CloneNotSupportedException {
        return (MutableVehicle) super.clone();
    }
}

This is Prototype: build a new instance by copying an existing one, then adjust what differs, rather than constructing from nothing each time.

What modern Java changes here

Object.clone() is close to dead code in idiomatic Java. Cloneable marks a class as cloneable without saying what cloning actually does to it. clone() throws a checked exception that has nothing to do with the type being cloned, and the copy it produces is shallow.

Suppose Vehicle grew a mutable field, a list of parking violations. A shallow clone() would hand the copy a reference to that same list, not a list of its own, and mutating one would silently mutate the other.

Records replace the whole mechanism with the canonical constructor itself as the copy point.

Vehicle nextFleetCar(Vehicle template, String registration) {
    return new Vehicle(registration, template.type());
}

This still names every field once, the same obligation clone() had, but there is no shallow-copy trap to fall into, because a record's fields are meant to be immutable already. A copy never accidentally shares mutable state the way clone() can. Some codebases write small withX helper methods for this by hand. Java does not yet generate them the way Kotlin's data class.copy() does, and that gap is the honest reason Prototype as clone() still comes up at all.

When naming it is wrong

Suppose building a new instance from scratch is already cheap, both fields already in hand at the call site. Then there is no copying problem to solve, and reaching for clone() adds a mechanism for a cost that does not exist yet. Even where copying genuinely helps, prefer a copy constructor or a small factory method over implementing Cloneable. The answer worth giving in an interview is "a constructor or static method that takes an existing instance and returns a modified copy," not "override clone()."

Where this lives in the app

The anchor given for this page is A2, corpus/parking-lot. Verified: A2 teaches Vehicle as an immutable, two-field record, and neither it nor any reference solution in this corpus builds a template-and-copy workflow or calls clone() anywhere. The fleet-car example above was built for this page from A2's real Vehicle record, not code that exists in the corpus.

What A2 actually shows is the reason a literal Prototype is unnecessary here. A value type with a handful of fields is cheap enough to reconstruct directly, which is most of why this pattern stays occasional rather than core.

All reference pages