Also known as Clone

Prototype

Intent

Prototype is a creational design pattern that lets you produce new objects by copying existing ones without compromising their internals.

Problem

You have an object and want to create a duplicate. How would you do it? First, you need to create a fresh object of the same class. Then you have to go over through all fields of the original object and copy their values to the new object.

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

There is one more problem with this approach. Since you have to know object's class to be able to go over all its fields, your code will become dependent on the classes of objects that you copy. You will not be able to copy objects if you only know their interfaces, but not the actual classes.

Solution

The Prototype pattern delegates cloning process to objects themselves.

It declares the 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

Industry vs Cell Division

In real life, prototypes are used for performing various tests before starting the mass production of a product. However, in this case, prototypes do not participate in the actual production, playing a passive role.

Since industrial prototypes do not copy themselves, the much closer analogy of the pattern is mitotic cell division (biology, remember?). 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.

Structure

Basic implementation

Prototype design pattern

Prototype registry implementation

Prototype pattern variety with a registry of prototypes
  1. Prototype declares the 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 provides easy access to frequently used prototypes, storing a pre-created set of objects, ready to be copied. Usually, it can be implemented with a simple name → prototype hash map. But for convenience, any other search criteria can be added to the registry.

Pseudocode

In this example, the Prototype is used for cloning objects that represent geometric shapes without coupling to their classes.

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(source: Shape) is
        if (source != null) then
            this.X = source.X;
            this.Y = source.Y;
            this.color = source.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(source: Rectangle) is
        // Parent constructor call is mandatory in order to copy private fields
        // defined in parent class.
        super(source)
        if (source != null) then
            this.width = source.width;
            this.height = source.height;

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


class Circle extends Shape is
    field radius: int

    method Circle(source: Circle) is
        super(source)
        if (source != null) then
            this.radius = source.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 classes of objects that you need to copy. For examples, when objects' classes are unknown since you work with them via an interface.

The Prototype pattern provides a client an interface to work with all prototypes. This interface is common for all objects that support cloning. It makes client code independent from concrete classes of products that it clones.

When you want to reduce the size of a class hierarchy that consists of similar objects, 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 configurations of an object.

Then, instead of instantiating a subclass that matches some configuration, client code looks for the appropriate prototype and clones it.

How to Implement

  1. Create the prototype interface and declare the clone method in it. You may simply add the method to all classes of existing class hierarchy, if you have one.

  2. Add an alternative constructor to all prototype classes, which accepts an object of a current class. The constructor must copy values of all fields defined in the class from the passed object to the current instance. Then it should call the parent constructor to take care of superclass fields.

    If your programming language does not support method overloading, you may define a special method for copying the data. The constructor is just more convenient since it delivers the copy right after using the new operator.

  3. The clone method usually consists of just one line: running a new operator using the prototype constructor. Note, that each class that supports cloning must explicitly override the clone method to use its class name along the new operator. Otherwise, cloning will produce an object of a parent class.

  4. Optionally, create a centralized prototype registry to store the catalog of frequently used prototypes. It may even store objects of the same class, configured in different ways.

    You can implement the registry as a new factory class or a factory method inside the base prototype class. The factory method should search for appropriate prototype based on the description that client code passes as an argument. 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.

    The last step would be eliminating direct calls to object constructors in favor of calls to the factory method of prototype registry.

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 are 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

  • Often, designs start out using Factory Method (less complicated, more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complex) as the designer discovers where more flexibility is needed.

  • Abstract Factory classes are often implemented with Factory Methods, but they can also be implemented using Prototype.

  • Prototype can help when you need to save copy of the Command into history.

  • Designs that make heavy use of the Composite and Decorator patterns often can benefit from Prototype as well. It would allow to clone complex structures, instead of re-constructing them from scratch.

  • Prototype doesn't require subclassing, but it does require an "initialize" operation. Factory Method requires subclassing, but doesn't require initialization step.

  • Prototype can be the simpler alternative to the Memento, if the object, which state you want to store in history, is fairly straightforward, doesn't have links to external resources, or if the links are easy to re-establish.

  • Abstract Factory, Builder and Prototype can be implemented as Singletons.

Implementations in Different Programming Languages

Java