Also known as Clone

Prototype

Intent

Allows producing new objects by copying existing ones.

Problem

How do we copy an object? First, we create a fresh object of the same class. Then we go over all object fields and copy their values to the new object.

Nice! But there's a catch. Not all objects can be copies this way. Some of the objects can have private fields not accessible from the outside.

There's one more problem with this approach. Since you need to know about all object fields, your code will become tightly coupled to all concrete classes of these objects.

Solution

The Prototype pattern delegates the cloning to the objects themselves.

It defines a common interface for all objects that allow cloning. It allows cloning objects without tight coupling to their concrete classes. Usually, the prototype interface contains a single clone method.

The implementation of clone method is similar for all classes. The method creates an object of a current class and copies all its field values into the new object. Most of the programming languages allow accessing private fields in an object of the same class, so the copying process is straightforward.

Objects that can be cloned are called prototypes. Sometimes, especially when your objects have a ton of fields and hundreds of possible configurations, prototypes can serve as an alternative to subclassing. In this case, the program creates a bunch of prototypes beforehand and then clones them instead of reconstructing objects from scratch.

Real-World Analogy

Mitotic division of a cell

In industrial production, product prototypes are used to perform various tests before launching production of the main batch. However, in this case, prototypes don't participate in the subsequent production, playing a passive role.

Mitotic cell division (biology) is a much closer example for this pattern. After such division, two completely identical cells are formed. The original cell acts as a prototype and takes an active role in creating a copy.

Clone troopers

A long time ago in a galaxy far, far away, the Republic used the DNA of a notorious mercenary to create an entire army of clones. All clones turned out to be the same, so it was easy to unify the tactical training, equipment, arms and transport.

P.S. A treat for Star Wars fans.

Structure

Basic implementation

Prototype pattern structure

Prototype registry implementation

Prototype pattern variety with a registry of prototypes
  1. Prototype defines a cloning interface. In most cases, a single clone method will be enough.

  2. Concrete prototype implements the cloning method. In addition to straightforward copying field values to a fresh clone, this method may solve some caveats, which should remain hidden for Clients. For example, cloning linked objects, untangling recursive dependencies, etc.

  3. Client uses the Prototype interface to retrieve an object's clone.

  4. Prototype registry (optional) stores predefined set of prototypes. Provides an easy way to find a particular prototype. Usually, it can be implemented with a simple name → prototype hash map.

Pseudocode

In this example, the Prototype allows cloning geometric shape objects. All shape classes implement the common cloning interface with a single cloning method. Subclasses call the parent cloning method and then copy their own fields to the resulting object.

Therefore, the Prototype design pattern allows client code to clone objects, even without knowing and independent of their specific classes.

// Base prototype.
abstract class Shape is
    field X: int
    field Y: int
    field color: string

    // A fresh object is initialized with values from the old object in
    // the constructor.
    method Shape(target: Shape) is
        if (target != null) then
            this.X = target.X;
            this.Y = target.Y;
            this.color = target.color;

    // Clone operation always returns one of the Shape subclasses.
    abstract method clone(): Shape


// Concrete prototype. Cloning method creates a new object and passes itself to
// the constructor. Until constructor is finished, has a reference to a fresh
// clone. Therefore, nobody has access to a partly built clone. This helps to
// make the cloning result consistent.
class Rectangle extends Shape is
    field width: int
    field height: int

    method Rectangle(target: Rectangle) is
        // Parent constructor call is mandatory in order to copy private fields
        // defined in parent class.
        super(target)
        if (target != null) then
            this.width = target.width;
            this.height = target.height;

    method clone(): Shape is
        return new Rectangle(this)


class Circle extends Shape is
    field radius: int

    method Circle(target: Circle) is
        super(target)
        if (target != null) then
            this.radius = target.radius;

    method clone(): Shape is
        return new Circle(this)


// Somewhere in client code.
class Application is
    field shapes: array of Shape

    method constructor() is
        Circle circle = new Circle();
        circle.X = 10
        circle.Y = 20
        circle.radius = 15
        shapes.add(circle);

        Circle anotherCircle = circle.clone();
        shapes.add(anotherCircle);
        // anotherCircle is the exact copy of circle.

        Rectangle rectangle = new Rectangle();
        rectangle.width = 10
        rectangle.height = 20
        shapes.add(rectangle);

    method businessLogic() is
        // Prototype rocks because it allows producing an object copy without
        // knowing anything about its type.
        Array shapesCopy = new Array of Shapes.

        // For instance, we don't know exact types of elements in shapes array.
        // We know they all of them are Shapes, that's all. But thanks to
        // polymorphism, when we call a clone method, it runs the method defined
        // in the class of that object. That's why we get proper clones instead
        // of the set of simple Shape objects.
        foreach shapes as shape do
            shapesCopy.add(shape.clone())

        // shapesCopy will contain exact copies of shape array children.

Applicability

When your code should not depend on the concrete product classes. For examples, when a concrete product type is unknown or can be changed in run time.

The Prototype pattern provides a client an interface to work with all prototypes. This interface is common for all products.

It makes the client code independent from the concrete classes of the products it clones.

When you want to reduce the size of a product hierarchy that consists of similar products, configured in different ways (in other words, each class would have unique field values).

The Prototype pattern allows creating a set of prototype objects that represent all possible product variants.

Then, instead of creating objects directly, client code would retrieve an appropriate prototype and clone it.

How to Implement

  1. Add a clone operation to your product hierarchy.

    If there's no such hierarchy, then create a cloning interface and define the clone operation in it. Then implement this interface in all of your products.

  2. Create a "registry" of prototype objects. It could contain objects of the same class, configured in different ways. You can put this registry into either a new factory class or a factory method inside a base product class.

  3. The factory method should search for appropriate prototype based on the description that client code passes into its parameters. It could be either just a string tag or a complex set of search criteria. After appropriate prototype had been found, it should clone it and return the copy to the client.

  4. Replace all direct constructor calls with the calls to the factory method.

Pros and Cons

  • Allows cloning objects without coupling to their concrete classes.
  • Reduces repeating initialization code.
  • Creates complex objects faster.
  • Provides an alternative for subclassing when you're dealing with complex objects having lots of configuration options.
  • Complex objects with lots of references to other objects can be difficult to clone.

Relations with Other Patterns

Implementations in Different Programming Languages

Java